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 4 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 @@ import {
BIGINT_0,
CLRequestFactory,
CLRequestType,
ConsolidationRequest,
DepositRequest,
KECCAK256_RLP,
KECCAK256_RLP_ARRAY,
Expand Down Expand Up @@ -424,6 +425,7 @@ export class Block {
withdrawals: withdrawalsData,
depositRequests,
withdrawalRequests,
consolidationRequests,
executionWitness,
} = payload

Expand Down Expand Up @@ -454,8 +456,13 @@ export class Block {

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>[])
: undefined

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

const requestsRoot = requests
? await Block.genRequestsTrieRoot(requests, new Trie({ common: opts?.common }))
Expand Down Expand Up @@ -1006,6 +1018,7 @@ export class Block {
// 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,
}

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

case CLRequestType.Consolidation:
executionPayload.consolidationRequests!.push((request as ConsolidationRequest).toJSON())
continue
}
}
} else if (
executionPayload.depositRequests !== undefined ||
executionPayload.withdrawalRequests !== undefined
executionPayload.withdrawalRequests !== undefined ||
executionPayload.consolidationRequests !== undefined
) {
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 @@ type BeaconWithdrawalRequest = {
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 @@ export type BeaconPayloadJson = {
// 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 @@ export function executionPayloadFromBeaconPayload(payload: BeaconPayloadJson): E
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,
}))
}

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
48 changes: 48 additions & 0 deletions packages/client/src/rpc/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,54 @@ export const validators = {
}
},

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 wt = params[index]
g11tech marked this conversation as resolved.
Show resolved Hide resolved

for (const field of requiredFields) {
if (wt[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
}

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

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

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

/**
* object validator to check if type is object with
* required keys and expected validation of values
Expand Down
22 changes: 16 additions & 6 deletions packages/client/test/rpc/engine/newPayloadV4.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ const [blockData] = blocks

const parentBeaconBlockRoot = '0x42942949c4ed512cd85c2cb54ca88591338cbb0564d3a2bea7961a639ef29d64'
const validForkChoiceState = {
headBlockHash: '0x3ff9144b3f0818580798b0a9ff5cedc1350ff62f46ec99b098344e2864be1e47',
safeBlockHash: '0x3ff9144b3f0818580798b0a9ff5cedc1350ff62f46ec99b098344e2864be1e47',
finalizedBlockHash: '0x3ff9144b3f0818580798b0a9ff5cedc1350ff62f46ec99b098344e2864be1e47',
headBlockHash: '0x5040e6b0056398536751c187683a3ecde8aff8fd9ea1d3450d687d7032134caf',
safeBlockHash: '0x5040e6b0056398536751c187683a3ecde8aff8fd9ea1d3450d687d7032134caf',
finalizedBlockHash: '0x5040e6b0056398536751c187683a3ecde8aff8fd9ea1d3450d687d7032134caf',
}
const validPayloadAttributes = {
timestamp: '0x64ba84fd',
Expand Down Expand Up @@ -63,9 +63,10 @@ describe(`${method}: call with executionPayloadV4`, () => {
excessBlobGas: '0x0',
depositRequests: [],
withdrawalRequests: [],
parentHash: '0x3ff9144b3f0818580798b0a9ff5cedc1350ff62f46ec99b098344e2864be1e47',
stateRoot: '0xd207043769091b6cdc91621f12bf2800b0b4643aeff09118fca52543c7a8ff03',
blockHash: '0xf9b4285204630ca183fec0a9a282cb68021af1aa9f3ab5f10d6b9ea8a7a3d4b6',
consolidationRequests: [],
parentHash: '0x5040e6b0056398536751c187683a3ecde8aff8fd9ea1d3450d687d7032134caf',
stateRoot: '0xbde9840c609ffa39cae0a2c9e354ac673920fcc2a5e6faeef5b78817c7fba7dd',
blockHash: '0x6b3ee4bb75e316427142bb9b48629e3e87ed8eea9f6d42b6aae296a11ec920b3',
}

const oldMethods = ['engine_newPayloadV1', 'engine_newPayloadV2', 'engine_newPayloadV3']
Expand Down Expand Up @@ -112,6 +113,10 @@ describe(`${method}: call with executionPayloadV4`, () => {
executionPayload.withdrawalRequests !== undefined,
'depositRequests field should be received'
)
assert.ok(
executionPayload.consolidationRequests !== undefined,
'consolidationRequests field should be received'
)

res = await rpc.request(method, [executionPayload, [], parentBeaconBlockRoot])
assert.equal(res.result.status, 'VALID')
Expand All @@ -138,6 +143,11 @@ const electraGenesisContracts = {
nonce: '1',
code: '0x3373fffffffffffffffffffffffffffffffffffffffe1460575767ffffffffffffffff5f3511605357600143035f3511604b575f35612000014311604b57611fff5f3516545f5260205ff35b5f5f5260205ff35b5f5ffd5b5f35611fff60014303165500',
},
'0x00b42dbF2194e931E80326D950320f7d9Dbeac02': {
balance: '0',
nonce: '1',
code: '0x3373fffffffffffffffffffffffffffffffffffffffe146098573615156028575f545f5260205ff35b36606014156101445760115f54600182026001905f5b5f82111560595781019083028483029004916001019190603e565b90939004341061014457600154600101600155600354806004026004013381556001015f35815560010160203581556001016040359055600101600355005b6003546002548082038060011160ac575060015b5f5b81811460f15780607402838201600402600401805490600101805490600101805490600101549260601b84529083601401528260340152906054015260010160ae565b9101809214610103579060025561010e565b90505f6002555f6003555b5f548061049d141561011d57505f5b6001546001828201116101325750505f610138565b01600190035b5f555f6001556074025ff35b5f5ffd',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the code for this new system contract to perform consolidations? Can we provide some minimal commentary on how it works?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, its fully explained in EIP in detail

},
'0x00A3ca265EBcb825B45F985A16CEFB49958cE017': {
balance: '0',
nonce: '1',
Expand Down
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