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

Block: treeshaking tasks #3586

Merged
merged 9 commits into from
Aug 14, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,27 @@ import {
} from '@ethereumjs/util'
import { keccak256 } from 'ethereum-cryptography/keccak.js'

import { genRequestsTrieRoot, genTransactionsTrieRoot, genWithdrawalsTrieRoot } from './helpers.js'

/* eslint-disable */
// This is to allow for a proper and linked collection of constructors for the class header.
// For tree shaking/code size this should be no problem since types go away on transpilation.
// TODO: See if there is an easier way to achieve the same result.
// See: https://github.com/microsoft/TypeScript/issues/47558
// (situation will eventually improve on Typescript and/or Eslint update)
import {
genRequestsTrieRoot,
genTransactionsTrieRoot,
genWithdrawalsTrieRoot,
BlockHeader,
type createBlockFromBeaconPayloadJson,
type createBlock,
type createBlockFromExecutionPayload,
type createBlockFromJsonRpcProvider,
type createBlockFromRLPSerializedBlock,
type createBlockFromRPC,
type createBlockFromValuesArray,
} from './index.js'
type createBlockFromBytesArray,
} from '../index.js'
/* eslint-enable */
import type { BlockBytes, BlockOptions, ExecutionPayload, JsonBlock } from './types.js'
import type { BlockBytes, BlockOptions, ExecutionPayload, JsonBlock } from '../types.js'
import type { Common } from '@ethereumjs/common'
import type {
FeeMarketEIP1559Transaction,
Expand All @@ -56,7 +57,7 @@ import type {
* (separate from the Block class to allow for tree shaking):
*
* - {@link createBlock }
* - {@link createBlockFromValuesArray }
* - {@link createBlockFromBytesArray }
* - {@link createBlockFromRLPSerializedBlock }
* - {@link createBlockFromRPC }
* - {@link createBlockFromJsonRpcProvider }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import {
CLRequestFactory,
ConsolidationRequest,
DepositRequest,
TypeOutput,
Withdrawal,
WithdrawalRequest,
bigIntToBytes,
bigIntToHex,
bytesToHex,
bytesToUtf8,
Expand All @@ -22,32 +22,34 @@ import {
hexToBytes,
intToHex,
isHexString,
setLengthLeft,
toBytes,
toType,
} from '@ethereumjs/util'

import { generateCliqueBlockExtraData } from './consensus/clique.js'
import { createBlockFromRpc } from './from-rpc.js'
import { generateCliqueBlockExtraData } from '../consensus/clique.js'
import { genRequestsTrieRoot, genTransactionsTrieRoot, genWithdrawalsTrieRoot } from '../helpers.js'
import {
genRequestsTrieRoot,
genTransactionsTrieRoot,
genWithdrawalsTrieRoot,
valuesArrayToHeaderData,
} from './helpers.js'

import { Block, BlockHeader, executionPayloadFromBeaconPayload } from './index.js'

import type { BeaconPayloadJson } from './from-beacon-payload.js'
Block,
blockHeaderFromRpc,
createBlockHeader,
createBlockHeaderFromBytesArray,
executionPayloadFromBeaconPayload,
} from '../index.js'

import type { BeaconPayloadJson } from '../from-beacon-payload.js'
import type {
BlockBytes,
BlockData,
BlockHeaderBytes,
BlockOptions,
ExecutionPayload,
ExecutionWitnessBytes,
HeaderData,
JsonRpcBlock,
RequestsBytes,
WithdrawalsBytes,
} from './types.js'
} from '../types.js'
import type { TypedTransaction } from '@ethereumjs/tx'
import type {
CLRequest,
CLRequestType,
Expand All @@ -57,71 +59,25 @@ import type {
WithdrawalBytes,
} from '@ethereumjs/util'

/**
* Static constructor to create a block header from a header data dictionary
*
* @param headerData
* @param opts
*/
export function createBlockHeader(headerData: HeaderData = {}, opts: BlockOptions = {}) {
return new BlockHeader(headerData, opts)
}
export function normalizeTxParams(_txParams: any) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Two things on this function:

  1. It isn't a constructor so ideally we put it in a helpers/utils file.
  2. We have essentially the same function here. Can we harmonize these two and consolidate in one location (maybe in @ethereumjs/util/helpers.ts or internal.ts) The only real difference I see is converting 0x0 to 0x in the transaction signatuere values.

Copy link
Member

Choose a reason for hiding this comment

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

Have put in a dedicated small issue #3587 so we can address in a separate PR

const txParams = Object.assign({}, _txParams)

/**
* Static constructor to create a block header from an array of Bytes values
*
* @param values
* @param opts
*/
export function createBlockHeaderFromValuesArray(
values: BlockHeaderBytes,
opts: BlockOptions = {},
) {
const headerData = valuesArrayToHeaderData(values)
const { number, baseFeePerGas, excessBlobGas, blobGasUsed, parentBeaconBlockRoot, requestsRoot } =
headerData
const header = createBlockHeader(headerData, opts)
if (header.common.isActivatedEIP(1559) && baseFeePerGas === undefined) {
const eip1559ActivationBlock = bigIntToBytes(header.common.eipBlock(1559)!)
if (
eip1559ActivationBlock !== undefined &&
equalsBytes(eip1559ActivationBlock, number as Uint8Array)
) {
throw new Error('invalid header. baseFeePerGas should be provided')
}
}
if (header.common.isActivatedEIP(4844)) {
if (excessBlobGas === undefined) {
throw new Error('invalid header. excessBlobGas should be provided')
} else if (blobGasUsed === undefined) {
throw new Error('invalid header. blobGasUsed should be provided')
}
}
if (header.common.isActivatedEIP(4788) && parentBeaconBlockRoot === undefined) {
throw new Error('invalid header. parentBeaconBlockRoot should be provided')
}
txParams.gasLimit = toType(txParams.gasLimit ?? txParams.gas, TypeOutput.BigInt)
txParams.data = txParams.data === undefined ? txParams.input : txParams.data

if (header.common.isActivatedEIP(7685) && requestsRoot === undefined) {
throw new Error('invalid header. requestsRoot should be provided')
}
return header
}
// check and convert gasPrice and value params
txParams.gasPrice = txParams.gasPrice !== undefined ? BigInt(txParams.gasPrice) : undefined
txParams.value = txParams.value !== undefined ? BigInt(txParams.value) : undefined

/**
* Static constructor to create a block header from a RLP-serialized header
*
* @param serializedHeaderData
* @param opts
*/
export function createBlockHeaderFromRLP(
serializedHeaderData: Uint8Array,
opts: BlockOptions = {},
) {
const values = RLP.decode(serializedHeaderData)
if (!Array.isArray(values)) {
throw new Error('Invalid serialized header input. Must be array')
}
return createBlockHeaderFromValuesArray(values as Uint8Array[], opts)
// strict byte length checking
txParams.to =
txParams.to !== null && txParams.to !== undefined
? setLengthLeft(toBytes(txParams.to), 20)
: null

txParams.v = toType(txParams.v, TypeOutput.BigInt)

return txParams
}

/**
Expand Down Expand Up @@ -193,15 +149,15 @@ export function createBlock(blockData: BlockData = {}, opts?: BlockOptions) {
* @param values
* @param opts
*/
export function createBlockFromValuesArray(values: BlockBytes, opts?: BlockOptions) {
export function createBlockFromBytesArray(values: BlockBytes, opts?: BlockOptions) {
if (values.length > 5) {
throw new Error(`invalid More values=${values.length} than expected were received (at most 5)`)
}

// First try to load header so that we can use its common (in case of setHardfork being activated)
// to correctly make checks on the hardforks
const [headerData, txsData, uhsData, ...valuesTail] = values
const header = createBlockHeaderFromValuesArray(headerData, opts)
const header = createBlockHeaderFromBytesArray(headerData, opts)

// conditional assignment of rest of values and splicing them out from the valuesTail
const withdrawalBytes = header.common.isActivatedEIP(4895)
Expand Down Expand Up @@ -266,7 +222,7 @@ export function createBlockFromValuesArray(values: BlockBytes, opts?: BlockOptio
uncleOpts.setHardfork = true
}
for (const uncleHeaderData of uhsData ?? []) {
uncleHeaders.push(createBlockHeaderFromValuesArray(uncleHeaderData, uncleOpts))
uncleHeaders.push(createBlockHeaderFromBytesArray(uncleHeaderData, uncleOpts))
}

const withdrawals = (withdrawalBytes as WithdrawalBytes[])
Expand Down Expand Up @@ -323,7 +279,7 @@ export function createBlockFromRLPSerializedBlock(serialized: Uint8Array, opts?:
throw new Error('Invalid serialized block input. Must be array')
}

return createBlockFromValuesArray(values, opts)
return createBlockFromBytesArray(values, opts)
}

/**
Expand All @@ -333,8 +289,31 @@ export function createBlockFromRLPSerializedBlock(serialized: Uint8Array, opts?:
* @param uncles - Optional list of Ethereum JSON RPC of uncles (eth_getUncleByBlockHashAndIndex)
* @param opts - An object describing the blockchain
*/
export function createBlockFromRPC(blockData: JsonRpcBlock, uncles?: any[], opts?: BlockOptions) {
return createBlockFromRpc(blockData, uncles, opts)
export function createBlockFromRPC(
blockParams: JsonRpcBlock,
uncles: any[] = [],
options?: BlockOptions,
) {
const header = blockHeaderFromRpc(blockParams, options)

const transactions: TypedTransaction[] = []
const opts = { common: header.common }
for (const _txParams of blockParams.transactions ?? []) {
const txParams = normalizeTxParams(_txParams)
const tx = createTxFromTxData(txParams, opts)
transactions.push(tx)
}

const uncleHeaders = uncles.map((uh) => blockHeaderFromRpc(uh, options))

const requests = blockParams.requests?.map((req) => {
const bytes = hexToBytes(req as PrefixedHexString)
return CLRequestFactory.fromSerializedRequest(bytes)
})
return createBlock(
{ header, transactions, uncleHeaders, withdrawals: blockParams.withdrawals, requests },
options,
)
}

/**
Expand Down Expand Up @@ -395,7 +374,7 @@ export const createBlockFromJsonRpcProvider = async (
}
}

return createBlockFromRpc(blockData, uncleHeaders, opts)
return createBlockFromRPC(blockData, uncleHeaders, opts)
}

/**
Expand Down Expand Up @@ -540,22 +519,3 @@ export function createSealedCliqueBlock(
}
return sealedCliqueBlock
}

export function createSealedCliqueBlockHeader(
headerData: HeaderData = {},
cliqueSigner: Uint8Array,
opts: BlockOptions = {},
): BlockHeader {
const sealedCliqueBlockHeader = new BlockHeader(headerData, {
...opts,
...{ skipConsensusFormatValidation: true },
})
;(sealedCliqueBlockHeader.extraData as any) = generateCliqueBlockExtraData(
sealedCliqueBlockHeader,
cliqueSigner,
)
if (opts.skipConsensusFormatValidation === false)
// We need to validate the consensus format here since we skipped it when constructing the block header
sealedCliqueBlockHeader['_consensusFormatValidation']()
return sealedCliqueBlockHeader
}
2 changes: 2 additions & 0 deletions packages/block/src/block/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './block.js'
export * from './constructors.js'
71 changes: 0 additions & 71 deletions packages/block/src/from-rpc.ts

This file was deleted.

Loading
Loading