Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into optimize-node-value…
Browse files Browse the repository at this point in the history
…-storage
  • Loading branch information
acolytec3 committed Jun 29, 2024
2 parents b87b924 + e31a65b commit 46377c8
Show file tree
Hide file tree
Showing 16 changed files with 363 additions and 85 deletions.
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
18 changes: 16 additions & 2 deletions packages/block/src/from-beacon-payload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,16 @@ type BeaconDepositRequest = {

type BeaconWithdrawalRequest = {
source_address: PrefixedHexString
validator_pub_key: PrefixedHexString
validator_pubkey: PrefixedHexString
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 @@ -160,10 +167,17 @@ export function executionPayloadFromBeaconPayload(payload: BeaconPayloadJson): E
if (payload.withdrawal_requests !== undefined && payload.withdrawal_requests !== null) {
executionPayload.withdrawalRequests = payload.withdrawal_requests.map((breq) => ({
sourceAddress: breq.source_address,
validatorPubkey: breq.validator_pub_key,
validatorPubkey: breq.validator_pubkey,
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
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 @@ export const validators = {
}
}

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 @@ export const validators = {
}

// 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]) {
const v = validate(field, this.bytes96)
if (v !== undefined) return v
}
Expand All @@ -494,10 +494,10 @@ export const validators = {
}
}

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 @@ -512,26 +512,74 @@ export const validators = {
}

// 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]) {
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]) {
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
}

// 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
}
}
}
},

/**
* object validator to check if type is object with
* required keys and expected validation of values
Expand Down
36 changes: 27 additions & 9 deletions packages/client/test/rpc/engine/newPayloadV4.spec.ts

Large diffs are not rendered by default.

30 changes: 29 additions & 1 deletion packages/common/src/eips.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ export const EIPs: EIPsDict = {
requiredEIPs: [],
vm: {
historyStorageAddress: {
v: BigInt('0x25a219378dad9b3503c8268c9ca836a52427a4fb'),
v: BigInt('0x0aae40965e6800cd9b1f4b05ff21581047e3f91e'),
d: 'The address where the historical blockhashes are stored',
},
historyServeWindow: {
Expand Down 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 All @@ -623,4 +644,11 @@ export const EIPs: EIPsDict = {
requiredEIPs: [3675],
gasPrices: {},
},
7709: {
comment: 'Use historical block hashes saved in state for BLOCKHASH',
url: 'https://eips.ethereum.org/EIPS/eip-7709',
status: Status.Draft,
minimumHardfork: Hardfork.Chainstart,
requiredEIPs: [2935],
},
}
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
3 changes: 2 additions & 1 deletion packages/evm/src/evm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +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,
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
9 changes: 5 additions & 4 deletions packages/evm/src/opcodes/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -608,23 +608,24 @@ export const handlers: Map<number, OpHandler> = new Map([
async function (runState, common) {
const number = runState.stack.pop()

if (common.isActivatedEIP(2935)) {
if (common.isActivatedEIP(7709)) {
if (number >= runState.interpreter.getBlockNumber()) {
runState.stack.push(BIGINT_0)
return
}

const diff = runState.interpreter.getBlockNumber() - number
const historyServeWindow = common.param('vm', 'historyServeWindow')
// block lookups must be within the `historyServeWindow`
if (diff > historyServeWindow || diff <= BIGINT_0) {
// block lookups must be within the original window even if historyStorageAddress's
// historyServeWindow is much greater than 256
if (diff > BIGINT_256 || diff <= BIGINT_0) {
runState.stack.push(BIGINT_0)
return
}

const historyAddress = new Address(
bigIntToAddressBytes(common.param('vm', 'historyStorageAddress'))
)
const historyServeWindow = common.param('vm', 'historyServeWindow')
const key = setLengthLeft(bigIntToBytes(number % historyServeWindow), 32)

if (common.isActivatedEIP(6800)) {
Expand Down
Loading

0 comments on commit 46377c8

Please sign in to comment.