Skip to content

Commit

Permalink
feat: add engine_getPayloadBodiesByHash and ByRange V2 (#6852)
Browse files Browse the repository at this point in the history
* Add ByHash and ByRange V2

* Fix build issue

* Fix CI error
  • Loading branch information
ensi321 authored and g11tech committed Aug 2, 2024
1 parent be00adf commit 4f6703c
Show file tree
Hide file tree
Showing 20 changed files with 59 additions and 48 deletions.
2 changes: 1 addition & 1 deletion packages/beacon-node/src/chain/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1147,7 +1147,7 @@ export class BeaconChain implements IBeaconChain {
// Will resolve this later
// if (cpEpoch >= (this.config.ELECTRA_FORK_EPOCH ?? Infinity)) {
// // finalizedState can be safely casted to Electra state since cp is already post-Electra
// if (finalizedState.eth1DepositIndex >= (finalizedState as CachedBeaconStateElectra).depositReceiptsStartIndex) {
// if (finalizedState.eth1DepositIndex >= (finalizedState as CachedBeaconStateElectra).depositRequestsStartIndex) {
// // Signal eth1 to stop polling eth1Data
// this.eth1.stopPollingEth1Data();
// }
Expand Down
4 changes: 2 additions & 2 deletions packages/beacon-node/src/eth1/eth1DepositDataTracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,9 @@ export class Eth1DepositDataTracker {
async getEth1DataAndDeposits(state: CachedBeaconStateAllForks): Promise<Eth1DataAndDeposits> {
if (
state.epochCtx.isAfterElectra() &&
state.eth1DepositIndex >= (state as CachedBeaconStateElectra).depositReceiptsStartIndex
state.eth1DepositIndex >= (state as CachedBeaconStateElectra).depositRequestsStartIndex
) {
// No need to poll eth1Data since Electra deprecates the mechanism after depositReceiptsStartIndex is reached
// No need to poll eth1Data since Electra deprecates the mechanism after depositRequestsStartIndex is reached
return {eth1Data: state.eth1Data, deposits: []};
}
const eth1Data = this.forcedEth1DataVote ?? (await this.getEth1Data(state));
Expand Down
9 changes: 6 additions & 3 deletions packages/beacon-node/src/execution/engine/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -418,8 +418,9 @@ export class ExecutionEngineHttp implements IExecutionEngine {
this.payloadIdCache.prune();
}

async getPayloadBodiesByHash(blockHashes: RootHex[]): Promise<(ExecutionPayloadBody | null)[]> {
const method = "engine_getPayloadBodiesByHashV1";
async getPayloadBodiesByHash(fork: ForkName, blockHashes: RootHex[]): Promise<(ExecutionPayloadBody | null)[]> {
const method =
ForkSeq[fork] >= ForkSeq.electra ? "engine_getPayloadBodiesByHashV2" : "engine_getPayloadBodiesByHashV1";
assertReqSizeLimit(blockHashes.length, 32);
const response = await this.rpc.fetchWithRetries<
EngineApiRpcReturnTypes[typeof method],
Expand All @@ -429,10 +430,12 @@ export class ExecutionEngineHttp implements IExecutionEngine {
}

async getPayloadBodiesByRange(
fork: ForkName,
startBlockNumber: number,
blockCount: number
): Promise<(ExecutionPayloadBody | null)[]> {
const method = "engine_getPayloadBodiesByRangeV1";
const method =
ForkSeq[fork] >= ForkSeq.electra ? "engine_getPayloadBodiesByRangeV2" : "engine_getPayloadBodiesByRangeV1";
assertReqSizeLimit(blockCount, 32);
const start = numToQuantity(startBlockNumber);
const count = numToQuantity(blockCount);
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
Expand Up @@ -174,7 +174,9 @@ export interface IExecutionEngine {
shouldOverrideBuilder?: boolean;
}>;

getPayloadBodiesByHash(blockHash: DATA[]): Promise<(ExecutionPayloadBody | null)[]>;
getPayloadBodiesByHash(fork: ForkName, blockHash: DATA[]): Promise<(ExecutionPayloadBody | null)[]>;

getPayloadBodiesByRange(start: number, count: number): Promise<(ExecutionPayloadBody | null)[]>;
getPayloadBodiesByRange(fork: ForkName, start: number, count: number): Promise<(ExecutionPayloadBody | null)[]>;

getState(): ExecutionEngineState;
}
2 changes: 2 additions & 0 deletions packages/beacon-node/src/execution/engine/mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,10 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend {
engine_getPayloadV3: this.getPayload.bind(this),
engine_getPayloadV4: this.getPayload.bind(this),
engine_getPayloadBodiesByHashV1: this.getPayloadBodiesByHash.bind(this),
engine_getPayloadBodiesByHashV2: this.getPayloadBodiesByHash.bind(this),
engine_getPayloadBodiesByRangeV1: this.getPayloadBodiesByRange.bind(this),
engine_getClientVersionV1: this.getClientVersionV1.bind(this),
engine_getPayloadBodiesByRangeV2: this.getPayloadBodiesByRange.bind(this),
};
}

Expand Down
10 changes: 7 additions & 3 deletions packages/beacon-node/src/execution/engine/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export type EngineApiRpcParamTypes = {
* 1. Array of DATA - Array of block_hash field values of the ExecutionPayload structure
* */
engine_getPayloadBodiesByHashV1: DATA[][];
engine_getPayloadBodiesByHashV2: DATA[][];

/**
* 1. start: QUANTITY, 64 bits - Starting block number
Expand All @@ -69,6 +70,7 @@ export type EngineApiRpcParamTypes = {
* Object - Instance of ClientVersion
*/
engine_getClientVersionV1: [ClientVersionRpc];
engine_getPayloadBodiesByRangeV2: [start: QUANTITY, count: QUANTITY];
};

export type PayloadStatus = {
Expand Down Expand Up @@ -107,10 +109,12 @@ export type EngineApiRpcReturnTypes = {
engine_getPayloadV4: ExecutionPayloadResponse;

engine_getPayloadBodiesByHashV1: (ExecutionPayloadBodyRpc | null)[];
engine_getPayloadBodiesByHashV2: (ExecutionPayloadBodyRpc | null)[];

engine_getPayloadBodiesByRangeV1: (ExecutionPayloadBodyRpc | null)[];

engine_getClientVersionV1: ClientVersionRpc[];
engine_getPayloadBodiesByRangeV2: (ExecutionPayloadBodyRpc | null)[];
};

type ExecutionPayloadRpcWithValue = {
Expand Down Expand Up @@ -235,8 +239,8 @@ export function serializeExecutionPayload(fork: ForkName, data: ExecutionPayload

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

Expand Down Expand Up @@ -334,7 +338,7 @@ export function parseExecutionPayload(
`depositRequests missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}`
);
}
(executionPayload as electra.ExecutionPayload).depositReceipts = depositRequests.map(deserializeDepositRequest);
(executionPayload as electra.ExecutionPayload).depositRequests = depositRequests.map(deserializeDepositRequest);

if (withdrawalRequests == null) {
throw Error(
Expand Down
10 changes: 5 additions & 5 deletions packages/beacon-node/test/sim/electra-interop.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,11 +219,11 @@ describe("executionEngine / ExecutionEngineHttp", function () {
}
}

if (payload.depositReceipts.length !== 1) {
throw Error(`Number of depositRequests mismatched. Expected: 1, actual: ${payload.depositReceipts.length}`);
if (payload.depositRequests.length !== 1) {
throw Error(`Number of depositRequests mismatched. Expected: 1, actual: ${payload.depositRequests.length}`);
}

const actualDepositRequest = payload.depositReceipts[0];
const actualDepositRequest = payload.depositRequests[0];
assert.deepStrictEqual(
actualDepositRequest,
depositRequestB,
Expand Down Expand Up @@ -431,8 +431,8 @@ describe("executionEngine / ExecutionEngineHttp", function () {
throw Error("Historical validator length for epoch 1 or 2 is not dropped properly");
}

if (headState.depositReceiptsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) {
throw Error("state.depositReceiptsStartIndex is not set upon processing new deposit receipt");
if (headState.depositRequestsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) {
throw Error("state.depositRequestsStartIndex is not set upon processing new deposit receipt");
}

// wait for 1 slot to print current epoch stats
Expand Down
2 changes: 1 addition & 1 deletion packages/beacon-node/test/spec/presets/operations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ const operations: TestRunnerFn<OperationsTestCase, BeaconStateAllForks> = (fork,
block: ssz[fork].BeaconBlock,
body: ssz[fork].BeaconBlockBody,
deposit: ssz.phase0.Deposit,
deposit_receipt: ssz.electra.DepositReceipt,
deposit_receipt: ssz.electra.DepositRequest,
proposer_slashing: ssz.phase0.ProposerSlashing,
voluntary_exit: ssz.phase0.SignedVoluntaryExit,
// Altair
Expand Down
4 changes: 2 additions & 2 deletions packages/beacon-node/test/unit/executionEngine/http.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ describe("ExecutionEngine / http", () => {

returnValue = response;

const res = await executionEngine.getPayloadBodiesByHash(reqBlockHashes);
const res = await executionEngine.getPayloadBodiesByHash(ForkName.bellatrix, reqBlockHashes);

expect(reqJsonRpcPayload).toEqual(request);
expect(res.map(serializeExecutionPayloadBody)).toEqual(response.result);
Expand Down Expand Up @@ -276,7 +276,7 @@ describe("ExecutionEngine / http", () => {

returnValue = response;

const res = await executionEngine.getPayloadBodiesByRange(startBlockNumber, blockCount);
const res = await executionEngine.getPayloadBodiesByRange(ForkName.bellatrix, startBlockNumber, blockCount);

expect(reqJsonRpcPayload).toEqual(request);
expect(res.map(serializeExecutionPayloadBody)).toEqual(response.result);
Expand Down
2 changes: 1 addition & 1 deletion packages/beacon-node/test/utils/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export function generateState(

if (forkSeq >= ForkSeq.electra) {
const stateElectra = state as electra.BeaconState;
stateElectra.depositReceiptsStartIndex = 2023n;
stateElectra.depositRequestsStartIndex = 2023n;
stateElectra.latestExecutionPayloadHeader = ssz.electra.ExecutionPayloadHeader.defaultValue();
}

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 @@ -115,8 +115,8 @@ export function upgradeLightClientHeader(

// eslint-disable-next-line no-fallthrough
case ForkName.electra:
(upgradedHeader as LightClientHeader<ForkName.electra>).execution.depositReceiptsRoot =
ssz.electra.LightClientHeader.fields.execution.fields.depositReceiptsRoot.defaultValue();
(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();

Expand Down Expand Up @@ -157,7 +157,7 @@ export function isValidLightClientHeader(config: ChainForkConfig, header: LightC

if (epoch < config.ELECTRA_FORK_EPOCH) {
if (
(header as LightClientHeader<ForkName.electra>).execution.depositReceiptsRoot !== undefined ||
(header as LightClientHeader<ForkName.electra>).execution.depositRequestsRoot !== undefined ||
(header as LightClientHeader<ForkName.electra>).execution.withdrawalRequestsRoot !== undefined
) {
return false;
Expand Down
4 changes: 2 additions & 2 deletions packages/state-transition/src/block/processDepositRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export function processDepositRequest(
state: CachedBeaconStateElectra,
depositRequest: electra.DepositRequest
): void {
if (state.depositReceiptsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) {
state.depositReceiptsStartIndex = BigInt(depositRequest.index);
if (state.depositRequestsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) {
state.depositRequestsStartIndex = BigInt(depositRequest.index);
}

applyDeposit(fork, state, depositRequest);
Expand Down
2 changes: 1 addition & 1 deletion packages/state-transition/src/block/processOperations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export function processOperations(
processExecutionLayerWithdrawalRequest(fork, state as CachedBeaconStateElectra, elWithdrawalRequest);
}

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

Expand Down
14 changes: 7 additions & 7 deletions packages/state-transition/src/slot/upgradeStateToElectra.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,16 @@ export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): Cache
stateElectraView.nextSyncCommittee = stateElectraCloned.nextSyncCommittee;
stateElectraView.latestExecutionPayloadHeader = ssz.electra.BeaconState.fields.latestExecutionPayloadHeader.toViewDU({
...stateElectraCloned.latestExecutionPayloadHeader.toValue(),
depositReceiptsRoot: ssz.Root.defaultValue(),
depositRequestsRoot: ssz.Root.defaultValue(),
withdrawalRequestsRoot: ssz.Root.defaultValue(),
});
stateElectraView.nextWithdrawalIndex = stateDeneb.nextWithdrawalIndex;
stateElectraView.nextWithdrawalValidatorIndex = stateDeneb.nextWithdrawalValidatorIndex;
stateElectraView.historicalSummaries = stateElectraCloned.historicalSummaries;

// latestExecutionPayloadHeader's depositReceiptsRoot and withdrawalRequestsRoot set to zeros by default
// default value of depositReceiptsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX
stateElectraView.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX;
// latestExecutionPayloadHeader's depositRequestsRoot and withdrawalRequestsRoot set to zeros by default
// default value of depositRequestsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX
stateElectraView.depositRequestsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX;
stateElectraView.depositBalanceToConsume = BigInt(0);
stateElectraView.exitBalanceToConsume = BigInt(0);

Expand Down Expand Up @@ -136,9 +136,9 @@ export function upgradeStateToElectraOriginal(stateDeneb: CachedBeaconStateDeneb
epoch: stateDeneb.epochCtx.epoch,
});

// 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;
// latestExecutionPayloadHeader's depositRequestsRoot and withdrawalRequestsRoot set to zeros by default
// default value of depositRequestsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX
stateElectra.depositRequestsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX;

const validatorsArr = stateElectra.validators.getAllReadonly();

Expand Down
4 changes: 2 additions & 2 deletions packages/state-transition/src/util/deposit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ export function getEth1DepositCount(state: CachedBeaconStateAllForks, eth1Data?:
// eth1DataIndexLimit = min(UintNum64, UintBn64) can be safely casted as UintNum64
// since the result lies within upper and lower bound of UintNum64
const eth1DataIndexLimit: UintNum64 =
eth1DataToUse.depositCount < electraState.depositReceiptsStartIndex
eth1DataToUse.depositCount < electraState.depositRequestsStartIndex
? eth1DataToUse.depositCount
: Number(electraState.depositReceiptsStartIndex);
: Number(electraState.depositRequestsStartIndex);

if (state.eth1DepositIndex < eth1DataIndexLimit) {
return Math.min(MAX_DEPOSITS, eth1DataIndexLimit - state.eth1DepositIndex);
Expand Down
4 changes: 2 additions & 2 deletions packages/state-transition/src/util/execution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,8 @@ export function executionPayloadToPayloadHeader(fork: ForkSeq, payload: Executio
}

if (fork >= ForkSeq.electra) {
(bellatrixPayloadFields as electra.ExecutionPayloadHeader).depositReceiptsRoot =
ssz.electra.DepositReceipts.hashTreeRoot((payload as electra.ExecutionPayload).depositReceipts);
(bellatrixPayloadFields as electra.ExecutionPayloadHeader).depositRequestsRoot =
ssz.electra.DepositRequests.hashTreeRoot((payload as electra.ExecutionPayload).depositRequests);
(bellatrixPayloadFields as electra.ExecutionPayloadHeader).withdrawalRequestsRoot =
ssz.electra.ExecutionLayerWithdrawalRequests.hashTreeRoot(
(payload as electra.ExecutionPayload).withdrawalRequests
Expand Down
2 changes: 1 addition & 1 deletion packages/state-transition/src/util/genesis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ export function initializeBeaconStateFromEth1(
stateElectra.latestExecutionPayloadHeader =
(executionPayloadHeader as CompositeViewDU<typeof ssz.electra.ExecutionPayloadHeader>) ??
ssz.electra.ExecutionPayloadHeader.defaultViewDU();
stateElectra.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX;
stateElectra.depositRequestsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX;
}

state.commit();
Expand Down
4 changes: 2 additions & 2 deletions packages/state-transition/test/unit/util/deposit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ describe("getEth1DepositCount", () => {
throw Error("Not a post-Electra state");
}

postElectraState.depositReceiptsStartIndex = 1000n;
postElectraState.depositRequestsStartIndex = 1000n;
postElectraState.eth1Data.depositCount = 995;

// 1. Should get less than MAX_DEPOSIT
Expand Down Expand Up @@ -77,7 +77,7 @@ describe("getEth1DepositCount", () => {
throw Error("Not a post-Electra state");
}

postElectraState.depositReceiptsStartIndex = 1000n;
postElectraState.depositRequestsStartIndex = 1000n;
postElectraState.eth1Data.depositCount = 1005;

// Before eth1DepositIndex reaching the start index
Expand Down
12 changes: 6 additions & 6 deletions packages/types/src/electra/sszTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,18 +112,18 @@ export const SignedAggregateAndProof = new ContainerType(
{typeName: "SignedAggregateAndProof", jsonCase: "eth2"}
);

export const DepositReceipt = new ContainerType(
export const DepositRequest = new ContainerType(
{
pubkey: BLSPubkey,
withdrawalCredentials: Bytes32,
amount: UintNum64,
signature: BLSSignature,
index: DepositIndex,
},
{typeName: "DepositReceipt", jsonCase: "eth2"}
{typeName: "DepositRequest", jsonCase: "eth2"}
);

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

export const ExecutionLayerWithdrawalRequest = new ContainerType(
{
Expand All @@ -141,7 +141,7 @@ export const ExecutionLayerWithdrawalRequests = new ListCompositeType(
export const ExecutionPayload = new ContainerType(
{
...denebSsz.ExecutionPayload.fields,
depositReceipts: DepositReceipts, // New in ELECTRA
depositRequests: DepositRequests, // New in ELECTRA
withdrawalRequests: ExecutionLayerWithdrawalRequests, // New in ELECTRA
},
{typeName: "ExecutionPayload", jsonCase: "eth2"}
Expand All @@ -150,7 +150,7 @@ export const ExecutionPayload = new ContainerType(
export const ExecutionPayloadHeader = new ContainerType(
{
...denebSsz.ExecutionPayloadHeader.fields,
depositReceiptsRoot: Root, // New in ELECTRA
depositRequestsRoot: Root, // New in ELECTRA
withdrawalRequestsRoot: Root, // New in ELECTRA
},
{typeName: "ExecutionPayloadHeader", jsonCase: "eth2"}
Expand Down Expand Up @@ -340,7 +340,7 @@ export const BeaconState = new ContainerType(
nextWithdrawalValidatorIndex: capellaSsz.BeaconState.fields.nextWithdrawalValidatorIndex,
// Deep history valid from Capella onwards
historicalSummaries: capellaSsz.BeaconState.fields.historicalSummaries,
depositReceiptsStartIndex: UintBn64, // New in ELECTRA:EIP6110
depositRequestsStartIndex: UintBn64, // New in ELECTRA:EIP6110
depositBalanceToConsume: Gwei, // New in Electra:EIP7251
exitBalanceToConsume: Gwei, // New in Electra:EIP7251
earliestExitEpoch: Epoch, // New in Electra:EIP7251
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 @@ -9,8 +9,8 @@ export type AttesterSlashing = ValueOf<typeof ssz.AttesterSlashing>;
export type AggregateAndProof = ValueOf<typeof ssz.AggregateAndProof>;
export type SignedAggregateAndProof = ValueOf<typeof ssz.SignedAggregateAndProof>;

export type DepositRequest = ValueOf<typeof ssz.DepositReceipt>;
export type DepositRequests = ValueOf<typeof ssz.DepositReceipts>;
export type DepositRequest = ValueOf<typeof ssz.DepositRequest>;
export type DepositRequests = ValueOf<typeof ssz.DepositRequests>;

export type ExecutionLayerWithdrawalRequest = ValueOf<typeof ssz.ExecutionLayerWithdrawalRequest>;
export type ExecutionLayerWithdrawalRequests = ValueOf<typeof ssz.ExecutionLayerWithdrawalRequests>;
Expand Down

0 comments on commit 4f6703c

Please sign in to comment.