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

util,block,client,evm,vm: add EIP 7251 el triggered consolidations request type #3477

Merged
merged 5 commits into from
Jun 29, 2024
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
22 changes: 20 additions & 2 deletions packages/block/src/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
BIGINT_0,
CLRequestFactory,
CLRequestType,
ConsolidationRequest,
DepositRequest,
KECCAK256_RLP,
KECCAK256_RLP_ARRAY,
Expand Down Expand Up @@ -424,6 +425,7 @@
withdrawals: withdrawalsData,
depositRequests,
withdrawalRequests,
consolidationRequests,
executionWitness,
} = payload

Expand Down Expand Up @@ -454,8 +456,13 @@

const hasDepositRequests = depositRequests !== undefined && depositRequests !== null
const hasWithdrawalRequests = withdrawalRequests !== undefined && withdrawalRequests !== null
const hasConsolidationRequests =
consolidationRequests !== undefined && consolidationRequests !== null

const requests =
hasDepositRequests || hasWithdrawalRequests ? ([] as CLRequest<CLRequestType>[]) : undefined
hasDepositRequests || hasWithdrawalRequests || hasConsolidationRequests
? ([] as CLRequest<CLRequestType>[])

Check warning on line 464 in packages/block/src/block.ts

View check run for this annotation

Codecov / codecov/patch

packages/block/src/block.ts#L464

Added line #L464 was not covered by tests
: undefined

if (depositRequests !== undefined && depositRequests !== null) {
for (const dJson of depositRequests) {
Expand All @@ -467,6 +474,11 @@
requests!.push(WithdrawalRequest.fromJSON(wJson))
}
}
if (consolidationRequests !== undefined && consolidationRequests !== null) {
for (const cJson of consolidationRequests) {
requests!.push(ConsolidationRequest.fromJSON(cJson))
}
}

Check warning on line 481 in packages/block/src/block.ts

View check run for this annotation

Codecov / codecov/patch

packages/block/src/block.ts#L478-L481

Added lines #L478 - L481 were not covered by tests

const requestsRoot = requests
? await Block.genRequestsTrieRoot(requests, new Trie({ common: opts?.common }))
Expand Down Expand Up @@ -1006,6 +1018,7 @@
// lets add the request fields first and then iterate over requests to fill them up
depositRequests: this.common.isActivatedEIP(6110) ? [] : undefined,
withdrawalRequests: this.common.isActivatedEIP(7002) ? [] : undefined,
consolidationRequests: this.common.isActivatedEIP(7251) ? [] : undefined,

Check warning on line 1021 in packages/block/src/block.ts

View check run for this annotation

Codecov / codecov/patch

packages/block/src/block.ts#L1021

Added line #L1021 was not covered by tests
}

if (this.requests !== undefined) {
Expand All @@ -1018,11 +1031,16 @@
case CLRequestType.Withdrawal:
executionPayload.withdrawalRequests!.push((request as WithdrawalRequest).toJSON())
continue

case CLRequestType.Consolidation:
executionPayload.consolidationRequests!.push((request as ConsolidationRequest).toJSON())
continue

Check warning on line 1037 in packages/block/src/block.ts

View check run for this annotation

Codecov / codecov/patch

packages/block/src/block.ts#L1034-L1037

Added lines #L1034 - L1037 were not covered by tests
}
}
} else if (
executionPayload.depositRequests !== undefined ||
executionPayload.withdrawalRequests !== undefined
executionPayload.withdrawalRequests !== undefined ||
executionPayload.consolidationRequests !== undefined

Check warning on line 1043 in packages/block/src/block.ts

View check run for this annotation

Codecov / codecov/patch

packages/block/src/block.ts#L1042-L1043

Added lines #L1042 - L1043 were not covered by tests
) {
throw Error(`Undefined requests for activated deposit or withdrawal requests`)
}
Expand Down
14 changes: 14 additions & 0 deletions packages/block/src/from-beacon-payload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@
amount: PrefixedHexString
}

type BeaconConsolidationRequest = {
source_address: PrefixedHexString
source_pubkey: PrefixedHexString
target_pubkey: PrefixedHexString
}

// Payload json that one gets using the beacon apis
// curl localhost:5052/eth/v2/beacon/blocks/56610 | jq .data.message.body.execution_payload
export type BeaconPayloadJson = {
Expand All @@ -48,6 +54,7 @@
// requests data
deposit_requests?: BeaconDepositRequest[]
withdrawal_requests?: BeaconWithdrawalRequest[]
consolidation_requests?: BeaconConsolidationRequest[]

// the casing of VerkleExecutionWitness remains same camel case for now
execution_witness?: VerkleExecutionWitness
Expand Down Expand Up @@ -164,6 +171,13 @@
amount: breq.amount,
}))
}
if (payload.consolidation_requests !== undefined && payload.consolidation_requests !== null) {
executionPayload.consolidationRequests = payload.consolidation_requests.map((breq) => ({
sourceAddress: breq.source_address,
sourcePubkey: breq.source_pubkey,
targetPubkey: breq.target_pubkey,
}))
}

Check warning on line 180 in packages/block/src/from-beacon-payload.ts

View check run for this annotation

Codecov / codecov/patch

packages/block/src/from-beacon-payload.ts#L175-L180

Added lines #L175 - L180 were not covered by tests

if (payload.execution_witness !== undefined && payload.execution_witness !== null) {
// the casing structure in payload could be camel case or snake depending upon the CL
Expand Down
2 changes: 2 additions & 0 deletions packages/block/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
BytesLike,
CLRequest,
CLRequestType,
ConsolidationRequestV1,
DepositRequestV1,
JsonRpcWithdrawal,
PrefixedHexString,
Expand Down Expand Up @@ -269,4 +270,5 @@ export type ExecutionPayload = {
executionWitness?: VerkleExecutionWitness | null // QUANTITY, 64 Bits, null implies not available
depositRequests?: DepositRequestV1[] // Array of 6110 deposit requests
withdrawalRequests?: WithdrawalRequestV1[] // Array of 7002 withdrawal requests
consolidationRequests?: ConsolidationRequestV1[] // Array of 7251 consolidation requests
}
2 changes: 1 addition & 1 deletion packages/block/test/eip7685block.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function getRandomDepositRequest(): CLRequest<CLRequestType> {
function getRandomWithdrawalRequest(): CLRequest<CLRequestType> {
const withdrawalRequestData = {
sourceAddress: randomBytes(20),
validatorPubkey: randomBytes(48),
validatorPublicKey: randomBytes(48),
amount: bytesToBigInt(randomBytes(8)),
}
return WithdrawalRequest.fromRequestData(withdrawalRequestData) as CLRequest<CLRequestType>
Expand Down
8 changes: 7 additions & 1 deletion packages/client/src/rpc/modules/engine/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ import { UNKNOWN_PAYLOAD } from '../../error-code.js'

import type { Skeleton } from '../../../service/index.js'
import type { Block, ExecutionPayload } from '@ethereumjs/block'
import type { DepositRequestV1, PrefixedHexString, WithdrawalRequestV1 } from '@ethereumjs/util'
import type {
ConsolidationRequestV1,
DepositRequestV1,
PrefixedHexString,
WithdrawalRequestV1,
} from '@ethereumjs/util'

export enum Status {
ACCEPTED = 'ACCEPTED',
Expand Down Expand Up @@ -31,6 +36,7 @@ export type ExecutionPayloadV3 = ExecutionPayloadV2 & { excessBlobGas: Uint64; b
export type ExecutionPayloadV4 = ExecutionPayloadV3 & {
depositRequests: DepositRequestV1[]
withdrawalRequests: WithdrawalRequestV1[]
consolidationRequests: ConsolidationRequestV1[]
}

export type ForkchoiceStateV1 = {
Expand Down
1 change: 1 addition & 0 deletions packages/client/src/rpc/modules/engine/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const executionPayloadV4FieldValidators = {
...executionPayloadV3FieldValidators,
depositRequests: validators.array(validators.depositRequest()),
withdrawalRequests: validators.array(validators.withdrawalRequest()),
consolidationRequests: validators.array(validators.consolidationRequest()),
}

export const forkchoiceFieldValidators = {
Expand Down
70 changes: 59 additions & 11 deletions packages/client/src/rpc/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -440,10 +440,10 @@
}
}

const wt = params[index]
const clReq = params[index]

for (const field of requiredFields) {
if (wt[field] === undefined) {
if (clReq[field] === undefined) {
return {
code: INVALID_PARAMS,
message: `invalid argument ${index}: required field ${field}`,
Expand All @@ -458,25 +458,25 @@
}

// validate pubkey
for (const field of [wt.pubkey]) {
for (const field of [clReq.pubkey]) {
const v = validate(field, this.bytes48)
if (v !== undefined) return v
}

// validate withdrawalCredentials
for (const field of [wt.withdrawalCredentials]) {
for (const field of [clReq.withdrawalCredentials]) {
const v = validate(field, this.bytes32)
if (v !== undefined) return v
}

// validate amount, index
for (const field of [wt.amount, wt.index]) {
for (const field of [clReq.amount, clReq.index]) {
const v = validate(field, this.bytes8)
if (v !== undefined) return v
}

// validate signature
for (const field of [wt.signature]) {
for (const field of [clReq.signature]) {

Check warning on line 479 in packages/client/src/rpc/validation.ts

View check run for this annotation

Codecov / codecov/patch

packages/client/src/rpc/validation.ts#L479

Added line #L479 was not covered by tests
const v = validate(field, this.bytes96)
if (v !== undefined) return v
}
Expand All @@ -494,10 +494,10 @@
}
}

const wt = params[index]
const clReq = params[index]

Check warning on line 497 in packages/client/src/rpc/validation.ts

View check run for this annotation

Codecov / codecov/patch

packages/client/src/rpc/validation.ts#L497

Added line #L497 was not covered by tests

for (const field of requiredFields) {
if (wt[field] === undefined) {
if (clReq[field] === undefined) {

Check warning on line 500 in packages/client/src/rpc/validation.ts

View check run for this annotation

Codecov / codecov/patch

packages/client/src/rpc/validation.ts#L500

Added line #L500 was not covered by tests
return {
code: INVALID_PARAMS,
message: `invalid argument ${index}: required field ${field}`,
Expand All @@ -512,26 +512,74 @@
}

// validate sourceAddress
for (const field of [wt.sourceAddress]) {
for (const field of [clReq.sourceAddress]) {
const v = validate(field, this.address)
if (v !== undefined) return v
}

// validate validatorPubkey
for (const field of [wt.validatorPubkey]) {
for (const field of [clReq.validatorPubkey]) {

Check warning on line 521 in packages/client/src/rpc/validation.ts

View check run for this annotation

Codecov / codecov/patch

packages/client/src/rpc/validation.ts#L521

Added line #L521 was not covered by tests
const v = validate(field, this.bytes48)
if (v !== undefined) return v
}

// validate amount
for (const field of [wt.amount]) {
for (const field of [clReq.amount]) {

Check warning on line 527 in packages/client/src/rpc/validation.ts

View check run for this annotation

Codecov / codecov/patch

packages/client/src/rpc/validation.ts#L527

Added line #L527 was not covered by tests
const v = validate(field, this.bytes8)
if (v !== undefined) return v
}
}
}
},

get consolidationRequest() {
return (requiredFields: string[] = ['sourceAddress', 'sourcePubkey', 'targetPubkey']) => {
return (params: any[], index: number) => {
if (typeof params[index] !== 'object') {
return {
code: INVALID_PARAMS,
message: `invalid argument ${index}: argument must be an object`,
}
}

const clReq = params[index]

for (const field of requiredFields) {
if (clReq[field] === undefined) {
return {
code: INVALID_PARAMS,
message: `invalid argument ${index}: required field ${field}`,
}
}
}

const validate = (field: any, validator: Function) => {
if (field === undefined) return
const v = validator([field], 0)
if (v !== undefined) return v
}

Check warning on line 561 in packages/client/src/rpc/validation.ts

View check run for this annotation

Codecov / codecov/patch

packages/client/src/rpc/validation.ts#L535-L561

Added lines #L535 - L561 were not covered by tests
// validate sourceAddress
for (const field of [clReq.sourceAddress]) {
const v = validate(field, this.address)
if (v !== undefined) return v
}

// validate validatorPubkey
for (const field of [clReq.sourcePubkey]) {
const v = validate(field, this.bytes48)
if (v !== undefined) return v
}

// validate amount
for (const field of [clReq.targetPubkey]) {
const v = validate(field, this.bytes48)
if (v !== undefined) return v
}
}
}
},

Check warning on line 582 in packages/client/src/rpc/validation.ts

View check run for this annotation

Codecov / codecov/patch

packages/client/src/rpc/validation.ts#L577-L582

Added lines #L577 - L582 were not covered by tests
/**
* object validator to check if type is object with
* required keys and expected validation of values
Expand Down
26 changes: 20 additions & 6 deletions packages/client/test/rpc/engine/newPayloadV4.spec.ts

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions packages/common/src/eips.ts
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,27 @@ export const EIPs: EIPsDict = {
},
},
},
7251: {
comment: 'Execution layer triggered consolidations (experimental)',
url: 'https://eips.ethereum.org/EIPS/eip-7251',
status: Status.Draft,
minimumHardfork: Hardfork.Paris,
requiredEIPs: [7685],
vm: {
consolidationRequestType: {
v: BigInt(0x02),
d: 'The withdrawal request type for EIP-7685',
},
systemAddress: {
v: BigInt('0xfffffffffffffffffffffffffffffffffffffffe'),
d: 'The system address to perform operations on the consolidation requests predeploy address',
},
consolidationRequestPredeployAddress: {
v: BigInt('0x00b42dbF2194e931E80326D950320f7d9Dbeac02'),
d: 'Address of the consolidations contract',
},
},
},
7516: {
comment: 'BLOBBASEFEE opcode',
url: 'https://eips.ethereum.org/EIPS/eip-7516',
Expand Down
2 changes: 1 addition & 1 deletion packages/common/src/hardforks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -841,7 +841,7 @@ export const hardforks: HardforksDict = {
'Next feature hardfork after cancun, internally used for pectra testing/implementation (incomplete/experimental)',
url: 'https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/prague.md',
status: Status.Draft,
eips: [2537, 2935, 3074, 6110, 7002, 7685],
eips: [2537, 2935, 3074, 6110, 7002, 7251, 7685],
},
osaka: {
name: 'osaka',
Expand Down
4 changes: 2 additions & 2 deletions packages/evm/src/evm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,8 @@ export class EVM implements EVMInterface {
// Supported EIPs
const supportedEIPs = [
1153, 1559, 2537, 2565, 2718, 2929, 2930, 2935, 3074, 3198, 3529, 3540, 3541, 3607, 3651,
3670, 3855, 3860, 4399, 4895, 4788, 4844, 5133, 5656, 6110, 6780, 6800, 7002, 7516, 7685,
7709,
3670, 3855, 3860, 4399, 4895, 4788, 4844, 5133, 5656, 6110, 6780, 6800, 7002, 7251, 7516,
7685, 7709,
]

for (const eip of this.common.eips()) {
Expand Down
Loading
Loading