From 73003e72d30eb81257cae232dc2ec4976d7a7c50 Mon Sep 17 00:00:00 2001 From: harkamal Date: Sun, 29 Sep 2024 17:43:05 +0530 Subject: [PATCH] convert requests to flat type across util,block and vm --- packages/block/README.md | 4 +- packages/block/examples/6110Requests.ts | 4 +- packages/block/src/block/block.ts | 44 ++------ packages/block/src/block/constructors.ts | 38 +------ packages/block/src/from-beacon-payload.ts | 51 +--------- packages/block/src/types.ts | 7 +- packages/block/test/eip7685block.spec.ts | 4 +- packages/util/src/request.ts | 113 ++++++++++----------- packages/vm/src/requests.ts | 34 +------ packages/vm/test/api/EIPs/eip-7685.spec.ts | 12 +-- 10 files changed, 78 insertions(+), 233 deletions(-) diff --git a/packages/block/README.md b/packages/block/README.md index a057f2d43a..aec0e2f64e 100644 --- a/packages/block/README.md +++ b/packages/block/README.md @@ -264,9 +264,9 @@ const main = async () => { const depositRequestData = { pubkey: randomBytes(48), withdrawalCredentials: randomBytes(32), - amount: bytesToBigInt(randomBytes(8)), + amount: (randomBytes(8)), signature: randomBytes(96), - index: bytesToBigInt(randomBytes(8)), + index: (randomBytes(8)), } const request = createDepositRequest(depositRequestData) as CLRequest const requests = [request] diff --git a/packages/block/examples/6110Requests.ts b/packages/block/examples/6110Requests.ts index e92feab960..56b831d9d2 100644 --- a/packages/block/examples/6110Requests.ts +++ b/packages/block/examples/6110Requests.ts @@ -18,9 +18,9 @@ const main = async () => { const depositRequestData = { pubkey: randomBytes(48), withdrawalCredentials: randomBytes(32), - amount: bytesToBigInt(randomBytes(8)), + amount: randomBytes(8), signature: randomBytes(96), - index: bytesToBigInt(randomBytes(8)), + index: randomBytes(8), } const request = createDepositRequest(depositRequestData) as CLRequest const requests = [request] diff --git a/packages/block/src/block/block.ts b/packages/block/src/block/block.ts index cf232e8ea3..47331a6c83 100644 --- a/packages/block/src/block/block.ts +++ b/packages/block/src/block/block.ts @@ -4,7 +4,6 @@ import { Trie } from '@ethereumjs/trie' import { Blob4844Tx, Capability } from '@ethereumjs/tx' import { BIGINT_0, - CLRequestType, KECCAK256_RLP, KECCAK256_RLP_ARRAY, bytesToHex, @@ -35,14 +34,7 @@ import { import type { BlockBytes, BlockOptions, ExecutionPayload, JSONBlock } from '../types.js' import type { Common } from '@ethereumjs/common' import type { FeeMarket1559Tx, LegacyTx, TypedTransaction } from '@ethereumjs/tx' -import type { - CLRequest, - ConsolidationRequest, - DepositRequest, - VerkleExecutionWitness, - Withdrawal, - WithdrawalRequest, -} from '@ethereumjs/util' +import type { CLRequest, CLRequestType, VerkleExecutionWitness, Withdrawal } from '@ethereumjs/util' /** * Class representing a block in the Ethereum network. The {@link BlockHeader} has its own @@ -545,6 +537,10 @@ export class Block { const header = blockJSON.header! const transactions = this.transactions.map((tx) => bytesToHex(tx.serialize())) ?? [] const withdrawalsArr = blockJSON.withdrawals ? { withdrawals: blockJSON.withdrawals } : {} + const executionRequestsArr = + this.requests !== undefined + ? { executionRequests: this.requests.map((req) => bytesToHex(req.serialize())) } + : undefined const executionPayload: ExecutionPayload = { blockNumber: header.number!, @@ -566,35 +562,7 @@ export class Block { ...withdrawalsArr, parentBeaconBlockRoot: header.parentBeaconBlockRoot, executionWitness: this.executionWitness, - - // 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) { - for (const request of this.requests) { - switch (request.type) { - case CLRequestType.Deposit: - executionPayload.depositRequests!.push((request as DepositRequest).toJSON()) - continue - - 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.consolidationRequests !== undefined - ) { - throw Error(`Undefined requests for activated deposit or withdrawal requests`) + ...executionRequestsArr, } return executionPayload diff --git a/packages/block/src/block/constructors.ts b/packages/block/src/block/constructors.ts index e9605cfeb9..a795094bf2 100644 --- a/packages/block/src/block/constructors.ts +++ b/packages/block/src/block/constructors.ts @@ -12,10 +12,7 @@ import { bigIntToHex, bytesToHex, bytesToUtf8, - createConsolidationRequestFromJSON, - createDepositRequestFromJSON, createWithdrawal, - createWithdrawalRequestFromJSON, equalsBytes, fetchFromProvider, getProvider, @@ -49,8 +46,6 @@ import type { } from '../types.js' import type { TypedTransaction } from '@ethereumjs/tx' import type { - CLRequest, - CLRequestType, EthersProvider, PrefixedHexString, RequestBytes, @@ -383,9 +378,7 @@ export async function createBlockFromExecutionPayload( feeRecipient: coinbase, transactions, withdrawals: withdrawalsData, - depositRequests, - withdrawalRequests, - consolidationRequests, + executionRequests, executionWitness, } = payload @@ -408,32 +401,9 @@ export async function createBlockFromExecutionPayload( ? await genWithdrawalsTrieRoot(withdrawals, new Trie({ common: opts?.common })) : undefined - const hasDepositRequests = depositRequests !== undefined && depositRequests !== null - const hasWithdrawalRequests = withdrawalRequests !== undefined && withdrawalRequests !== null - const hasConsolidationRequests = - consolidationRequests !== undefined && consolidationRequests !== null - - const requests = - hasDepositRequests || hasWithdrawalRequests || hasConsolidationRequests - ? ([] as CLRequest[]) - : undefined - - if (depositRequests !== undefined && depositRequests !== null) { - for (const dJSON of depositRequests) { - requests!.push(createDepositRequestFromJSON(dJSON)) - } - } - if (withdrawalRequests !== undefined && withdrawalRequests !== null) { - for (const wJSON of withdrawalRequests) { - requests!.push(createWithdrawalRequestFromJSON(wJSON)) - } - } - if (consolidationRequests !== undefined && consolidationRequests !== null) { - for (const cJSON of consolidationRequests) { - requests!.push(createConsolidationRequestFromJSON(cJSON)) - } - } - + const requests = executionRequests?.map((req) => + CLRequestFactory.fromSerializedRequest(hexToBytes(req)), + ) const keccakFunction = opts?.common?.customCrypto.keccak256 ?? keccak256 const requestsRoot = requests ? await genRequestsRoot(requests, keccakFunction) : undefined diff --git a/packages/block/src/from-beacon-payload.ts b/packages/block/src/from-beacon-payload.ts index d6d93467f6..a6ff816b8f 100644 --- a/packages/block/src/from-beacon-payload.ts +++ b/packages/block/src/from-beacon-payload.ts @@ -10,26 +10,6 @@ type BeaconWithdrawal = { amount: PrefixedHexString } -type BeaconDepositRequest = { - pubkey: PrefixedHexString - withdrawal_credentials: PrefixedHexString - amount: PrefixedHexString - signature: PrefixedHexString - index: PrefixedHexString -} - -type BeaconWithdrawalRequest = { - source_address: 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 = { @@ -52,10 +32,7 @@ export type BeaconPayloadJSON = { excess_blob_gas?: NumericString parent_beacon_block_root?: PrefixedHexString // requests data - deposit_requests?: BeaconDepositRequest[] - withdrawal_requests?: BeaconWithdrawalRequest[] - consolidation_requests?: BeaconConsolidationRequest[] - + execution_requests?: PrefixedHexString[] // the casing of VerkleExecutionWitness remains same camel case for now execution_witness?: VerkleExecutionWitness } @@ -158,30 +135,8 @@ export function executionPayloadFromBeaconPayload(payload: BeaconPayloadJSON): E } // requests - if (payload.deposit_requests !== undefined && payload.deposit_requests !== null) { - executionPayload.depositRequests = payload.deposit_requests.map((beaconRequest) => ({ - pubkey: beaconRequest.pubkey, - withdrawalCredentials: beaconRequest.withdrawal_credentials, - amount: beaconRequest.amount, - signature: beaconRequest.signature, - index: beaconRequest.index, - })) - } - if (payload.withdrawal_requests !== undefined && payload.withdrawal_requests !== null) { - executionPayload.withdrawalRequests = payload.withdrawal_requests.map((beaconRequest) => ({ - sourceAddress: beaconRequest.source_address, - validatorPubkey: beaconRequest.validator_pubkey, - amount: beaconRequest.amount, - })) - } - if (payload.consolidation_requests !== undefined && payload.consolidation_requests !== null) { - executionPayload.consolidationRequests = payload.consolidation_requests.map( - (beaconRequest) => ({ - sourceAddress: beaconRequest.source_address, - sourcePubkey: beaconRequest.source_pubkey, - targetPubkey: beaconRequest.target_pubkey, - }), - ) + if (payload.execution_requests !== undefined && payload.execution_requests !== null) { + executionPayload.executionRequests = payload.execution_requests } if (payload.execution_witness !== undefined && payload.execution_witness !== null) { diff --git a/packages/block/src/types.ts b/packages/block/src/types.ts index 145ef4ef20..50db8f09f2 100644 --- a/packages/block/src/types.ts +++ b/packages/block/src/types.ts @@ -7,8 +7,6 @@ import type { BytesLike, CLRequest, CLRequestType, - ConsolidationRequestV1, - DepositRequestV1, JSONRPCWithdrawal, NumericString, PrefixedHexString, @@ -16,7 +14,6 @@ import type { VerkleExecutionWitness, WithdrawalBytes, WithdrawalData, - WithdrawalRequestV1, } from '@ethereumjs/util' /** @@ -274,7 +271,5 @@ export type ExecutionPayload = { parentBeaconBlockRoot?: PrefixedHexString // QUANTITY, 64 Bits // VerkleExecutionWitness is already a hex serialized object 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 + executionRequests?: PrefixedHexString[] | null // null implies not available } diff --git a/packages/block/test/eip7685block.spec.ts b/packages/block/test/eip7685block.spec.ts index 4c0c21e646..4355cdb1b2 100644 --- a/packages/block/test/eip7685block.spec.ts +++ b/packages/block/test/eip7685block.spec.ts @@ -25,9 +25,9 @@ function getRandomDepositRequest(): CLRequest { const depositRequestData = { pubkey: randomBytes(48), withdrawalCredentials: randomBytes(32), - amount: bytesToBigInt(randomBytes(8)), + amount: randomBytes(8), signature: randomBytes(96), - index: bytesToBigInt(randomBytes(8)), + index: randomBytes(8), } return createDepositRequest(depositRequestData) as CLRequest } diff --git a/packages/util/src/request.ts b/packages/util/src/request.ts index 66e359e435..957083e3e0 100644 --- a/packages/util/src/request.ts +++ b/packages/util/src/request.ts @@ -1,15 +1,7 @@ import { RLP } from '@ethereumjs/rlp' import { concatBytes } from 'ethereum-cryptography/utils' -import { - bigIntToBytes, - bigIntToHex, - bytesToBigInt, - bytesToHex, - hexToBigInt, - hexToBytes, -} from './bytes.js' -import { BIGINT_0 } from './constants.js' +import { bytesToHex, hexToBytes } from './bytes.js' import type { PrefixedHexString } from './types.js' @@ -50,15 +42,18 @@ export interface RequestJSON { export type DepositRequestData = { pubkey: Uint8Array withdrawalCredentials: Uint8Array - amount: bigint + // 8 bytes uint64 LE + amount: Uint8Array signature: Uint8Array - index: bigint + // 8 bytes uint64 LE + index: Uint8Array } export type WithdrawalRequestData = { sourceAddress: Uint8Array validatorPubkey: Uint8Array - amount: bigint + // 8 bytes uint64 LE + amount: Uint8Array } export type ConsolidationRequestData = { @@ -94,27 +89,23 @@ export class DepositRequest extends CLRequest { constructor( public readonly pubkey: Uint8Array, public readonly withdrawalCredentials: Uint8Array, - public readonly amount: bigint, + // 8 bytes uint64 LE + public readonly amount: Uint8Array, public readonly signature: Uint8Array, - public readonly index: bigint, + // 8 bytes uint64 LE + public readonly index: Uint8Array, ) { super(CLRequestType.Deposit) } serialize() { - const indexBytes = this.index === BIGINT_0 ? new Uint8Array() : bigIntToBytes(this.index) - - const amountBytes = this.amount === BIGINT_0 ? new Uint8Array() : bigIntToBytes(this.amount) - return concatBytes( Uint8Array.from([this.type]), - RLP.encode([ - this.pubkey, - this.withdrawalCredentials, - amountBytes, - this.signature, - indexBytes, - ]), + this.pubkey, + this.withdrawalCredentials, + this.amount, + this.signature, + this.index, ) } @@ -122,9 +113,9 @@ export class DepositRequest extends CLRequest { return { pubkey: bytesToHex(this.pubkey), withdrawalCredentials: bytesToHex(this.withdrawalCredentials), - amount: bigIntToHex(this.amount), + amount: bytesToHex(this.amount), signature: bytesToHex(this.signature), - index: bigIntToHex(this.index), + index: bytesToHex(this.index), } } } @@ -133,17 +124,18 @@ export class WithdrawalRequest extends CLRequest { constructor( public readonly sourceAddress: Uint8Array, public readonly validatorPubkey: Uint8Array, - public readonly amount: bigint, + // 8 bytes uint64 LE + public readonly amount: Uint8Array, ) { super(CLRequestType.Withdrawal) } serialize() { - const amountBytes = this.amount === BIGINT_0 ? new Uint8Array() : bigIntToBytes(this.amount) - return concatBytes( Uint8Array.from([this.type]), - RLP.encode([this.sourceAddress, this.validatorPubkey, amountBytes]), + this.sourceAddress, + this.validatorPubkey, + this.amount, ) } @@ -151,7 +143,7 @@ export class WithdrawalRequest extends CLRequest { return { sourceAddress: bytesToHex(this.sourceAddress), validatorPubkey: bytesToHex(this.validatorPubkey), - amount: bigIntToHex(this.amount), + amount: bytesToHex(this.amount), } } } @@ -168,7 +160,9 @@ export class ConsolidationRequest extends CLRequest serialize() { return concatBytes( Uint8Array.from([this.type]), - RLP.encode([this.sourceAddress, this.sourcePubkey, this.targetPubkey]), + this.sourceAddress, + this.sourcePubkey, + this.targetPubkey, ) } @@ -191,26 +185,23 @@ export function createDepositRequestFromJSON(jsonData: DepositRequestV1): Deposi return createDepositRequest({ pubkey: hexToBytes(pubkey), withdrawalCredentials: hexToBytes(withdrawalCredentials), - amount: hexToBigInt(amount), + amount: hexToBytes(amount), signature: hexToBytes(signature), - index: hexToBigInt(index), + index: hexToBytes(index), }) } -export function createDepositRequestFromRLP(bytes: Uint8Array): DepositRequest { - const [pubkey, withdrawalCredentials, amount, signature, index] = RLP.decode(bytes) as [ - Uint8Array, - Uint8Array, - Uint8Array, - Uint8Array, - Uint8Array, - ] +export function createDepositRequestFromFlatData(bytes: Uint8Array): DepositRequest { + if (bytes.length !== 48 + 32 + 8 + 96) { + throw Error(`Invalid bytes=${bytes.length} for deposit request data`) + } + return createDepositRequest({ - pubkey, - withdrawalCredentials, - amount: bytesToBigInt(amount), - signature, - index: bytesToBigInt(index), + pubkey: bytes.subarray(0, 48), + withdrawalCredentials: bytes.subarray(48, 48 + 32), + amount: bytes.subarray(48 + 32, 48 + 32 + 8), + signature: bytes.subarray(48 + 32 + 8, 48 + 32 + 8 + 96), + index: bytes.subarray(48 + 32 + 8 + 96), }) } @@ -224,20 +215,18 @@ export function createWithdrawalRequestFromJSON(jsonData: WithdrawalRequestV1): return createWithdrawalRequest({ sourceAddress: hexToBytes(sourceAddress), validatorPubkey: hexToBytes(validatorPubkey), - amount: hexToBigInt(amount), + amount: hexToBytes(amount), }) } -export function createWithdrawalRequestFromRLP(bytes: Uint8Array): WithdrawalRequest { - const [sourceAddress, validatorPubkey, amount] = RLP.decode(bytes) as [ - Uint8Array, - Uint8Array, - Uint8Array, - ] +export function createWithdrawalRequestFromFlatData(bytes: Uint8Array): WithdrawalRequest { + if (bytes.length !== 20 + 48 + 8) { + throw Error(`Invalid bytes=${bytes.length} for withdrawal request data`) + } return createWithdrawalRequest({ - sourceAddress, - validatorPubkey, - amount: bytesToBigInt(amount), + sourceAddress: bytes.subarray(0, 20), + validatorPubkey: bytes.subarray(20, 20 + 48), + amount: bytes.subarray(20 + 48), }) } @@ -259,7 +248,7 @@ export function createConsolidationRequestFromJSON( }) } -export function createConsolidationRequestFromRLP(bytes: Uint8Array): ConsolidationRequest { +export function createConsolidationRequestFromFlatData(bytes: Uint8Array): ConsolidationRequest { const [sourceAddress, sourcePubkey, targetPubkey] = RLP.decode(bytes) as [ Uint8Array, Uint8Array, @@ -276,11 +265,11 @@ export class CLRequestFactory { public static fromSerializedRequest(bytes: Uint8Array): CLRequest { switch (bytes[0]) { case CLRequestType.Deposit: - return createDepositRequestFromRLP(bytes.subarray(1)) + return createDepositRequestFromFlatData(bytes.subarray(1)) case CLRequestType.Withdrawal: - return createWithdrawalRequestFromRLP(bytes.subarray(1)) + return createWithdrawalRequestFromFlatData(bytes.subarray(1)) case CLRequestType.Consolidation: - return createConsolidationRequestFromRLP(bytes.subarray(1)) + return createConsolidationRequestFromFlatData(bytes.subarray(1)) default: throw Error(`Invalid request type=${bytes[0]}`) } diff --git a/packages/vm/src/requests.ts b/packages/vm/src/requests.ts index 54230e18bc..9b135fdef3 100644 --- a/packages/vm/src/requests.ts +++ b/packages/vm/src/requests.ts @@ -2,7 +2,6 @@ import { Mainnet } from '@ethereumjs/common' import { bigIntToAddressBytes, bigIntToBytes, - bytesToBigInt, bytesToHex, bytesToInt, createAddressFromString, @@ -10,7 +9,6 @@ import { createDepositRequest, createWithdrawalRequest, setLengthLeft, - unpadBytes, } from '@ethereumjs/util' import type { RunTxResult } from './types.js' @@ -95,7 +93,7 @@ const accumulateEIP7002Requests = async ( const slicedBytes = resultsBytes.slice(startByte, startByte + 76) const sourceAddress = slicedBytes.slice(0, 20) // 20 Bytes const validatorPubkey = slicedBytes.slice(20, 68) // 48 Bytes - const amount = bytesToBigInt(unpadBytes(slicedBytes.slice(68, 76))) // 8 Bytes / Uint64 + const amount = slicedBytes.slice(68, 76) // 8 Bytes / Uint64 LE requests.push(createWithdrawalRequest({ sourceAddress, validatorPubkey, amount })) } } @@ -176,40 +174,16 @@ const accumulateDeposits = async ( const sigSize = bytesToInt(log[2].slice(sigIdx, sigIdx + 32)) const indexIdx = bytesToInt(log[2].slice(128, 160)) const indexSize = bytesToInt(log[2].slice(indexIdx, indexIdx + 32)) + const pubkey = log[2].slice(pubKeyIdx + 32, pubKeyIdx + 32 + pubKeySize) const withdrawalCredentials = log[2].slice( withdrawalCreditsIdx + 32, withdrawalCreditsIdx + 32 + withdrawalCreditsSize, ) - const amountBytes = log[2].slice(amountIdx + 32, amountIdx + 32 + amountSize) - const amountBytesBigEndian = new Uint8Array([ - amountBytes[7], - amountBytes[6], - amountBytes[5], - amountBytes[4], - amountBytes[3], - amountBytes[2], - amountBytes[1], - amountBytes[0], - ]) - const amount = bytesToBigInt(amountBytesBigEndian) - + const amount = log[2].slice(amountIdx + 32, amountIdx + 32 + amountSize) const signature = log[2].slice(sigIdx + 32, sigIdx + 32 + sigSize) + const index = log[2].slice(indexIdx + 32, indexIdx + 32 + indexSize) - const indexBytes = log[2].slice(indexIdx + 32, indexIdx + 32 + indexSize) - - // Convert the little-endian array to big-endian array - const indexBytesBigEndian = new Uint8Array([ - indexBytes[7], - indexBytes[6], - indexBytes[5], - indexBytes[4], - indexBytes[3], - indexBytes[2], - indexBytes[1], - indexBytes[0], - ]) - const index = bytesToBigInt(indexBytesBigEndian) requests.push( createDepositRequest({ pubkey, diff --git a/packages/vm/test/api/EIPs/eip-7685.spec.ts b/packages/vm/test/api/EIPs/eip-7685.spec.ts index d330f55533..27003c7381 100644 --- a/packages/vm/test/api/EIPs/eip-7685.spec.ts +++ b/packages/vm/test/api/EIPs/eip-7685.spec.ts @@ -1,13 +1,7 @@ import { createBlock, genRequestsRoot } from '@ethereumjs/block' import { createBlockchain } from '@ethereumjs/blockchain' import { Common, Hardfork, Mainnet } from '@ethereumjs/common' -import { - KECCAK256_RLP, - bytesToBigInt, - createDepositRequest, - hexToBytes, - randomBytes, -} from '@ethereumjs/util' +import { KECCAK256_RLP, createDepositRequest, hexToBytes, randomBytes } from '@ethereumjs/util' import { keccak256 } from 'ethereum-cryptography/keccak.js' import { assert, describe, expect, it } from 'vitest' @@ -23,9 +17,9 @@ function getRandomDepositRequest(): CLRequest { const depositRequestData = { pubkey: randomBytes(48), withdrawalCredentials: randomBytes(32), - amount: bytesToBigInt(randomBytes(8)), + amount: randomBytes(8), signature: randomBytes(96), - index: bytesToBigInt(randomBytes(8)), + index: randomBytes(8), } return createDepositRequest(depositRequestData) as CLRequest }