diff --git a/packages/vm/src/runTx.ts b/packages/vm/src/runTx.ts index 38d05486e0..8101d8371c 100644 --- a/packages/vm/src/runTx.ts +++ b/packages/vm/src/runTx.ts @@ -1,4 +1,4 @@ -import { cliqueSigner, createEmptyBlock } from '@ethereumjs/block' +import { cliqueSigner, createBlockHeader } from '@ethereumjs/block' import { ConsensusType, Hardfork } from '@ethereumjs/common' import { RLP } from '@ethereumjs/rlp' import { Blob4844Tx, Capability, isBlob4844Tx } from '@ethereumjs/tx' @@ -51,6 +51,8 @@ import type { const debug = debugDefault('vm:tx') const debugGas = debugDefault('vm:tx:gas') +const DEFAULT_HEADER = createBlockHeader() + let enableProfiler = false const initLabel = 'EVM journal init, address/slot warming, fee validation' const balanceNonceLabel = 'Balance/Nonce checks and update' @@ -80,10 +82,7 @@ export async function runTx(vm: VM, opts: RunTxOpts): Promise { console.time(entireTxLabel) } - // create a reasonable default if no block is given - opts.block = opts.block ?? createEmptyBlock({}, { common: vm.common }) - - if (opts.skipHardForkValidation !== true) { + if (opts.skipHardForkValidation !== true && opts.block !== undefined) { // If block and tx don't have a same hardfork, set tx hardfork to block if (opts.tx.common.hardfork() !== opts.block.common.hardfork()) { opts.tx.common.setHardfork(opts.block.common.hardfork()) @@ -95,7 +94,8 @@ export async function runTx(vm: VM, opts: RunTxOpts): Promise { } } - if (opts.skipBlockGasLimitValidation !== true && opts.block.header.gasLimit < opts.tx.gasLimit) { + const gasLimit = opts.block?.header.gasLimit ?? DEFAULT_HEADER.gasLimit + if (opts.skipBlockGasLimitValidation !== true && gasLimit < opts.tx.gasLimit) { const msg = _errorMsg('tx has a higher gas limit than the block', vm, opts.block, opts.tx) throw new Error(msg) } @@ -198,10 +198,6 @@ async function _runTx(vm: VM, opts: RunTxOpts): Promise { const { tx, block } = opts - if (!block) { - throw new Error('block required') - } - /** * The `beforeTx` event * @@ -232,7 +228,8 @@ async function _runTx(vm: VM, opts: RunTxOpts): Promise { vm.evm.journal.addAlwaysWarmAddress(bytesToUnprefixedHex(tx.to.bytes)) } if (vm.common.isActivatedEIP(3651)) { - vm.evm.journal.addAlwaysWarmAddress(bytesToUnprefixedHex(block.header.coinbase.bytes)) + const coinbase = block?.header.coinbase.bytes ?? DEFAULT_HEADER.coinbase.bytes + vm.evm.journal.addAlwaysWarmAddress(bytesToUnprefixedHex(coinbase)) } } @@ -260,7 +257,7 @@ async function _runTx(vm: VM, opts: RunTxOpts): Promise { // Ensure that the user was willing to at least pay the base fee // assert transaction.max_fee_per_gas >= block.base_fee_per_gas const maxFeePerGas = 'maxFeePerGas' in tx ? tx.maxFeePerGas : tx.gasPrice - const baseFeePerGas = block.header.baseFeePerGas! + const baseFeePerGas = block?.header.baseFeePerGas ?? DEFAULT_HEADER.baseFeePerGas! if (maxFeePerGas < baseFeePerGas) { const msg = _errorMsg( `Transaction's ${ @@ -296,7 +293,8 @@ async function _runTx(vm: VM, opts: RunTxOpts): Promise { } // Check balance against upfront tx cost - const upFrontCost = tx.getUpfrontCost(block.header.baseFeePerGas) + const baseFeePerGas = block?.header.baseFeePerGas ?? DEFAULT_HEADER.baseFeePerGas + const upFrontCost = tx.getUpfrontCost(baseFeePerGas) if (balance < upFrontCost) { if (opts.skipBalance === true && fromAccount.balance < upFrontCost) { if (tx.supports(Capability.EIP1559FeeMarket) === false) { @@ -339,16 +337,7 @@ async function _runTx(vm: VM, opts: RunTxOpts): Promise { maxCost += totalblobGas * castTx.maxFeePerBlobGas // 4844 minimum blobGas price check - if (opts.block === undefined) { - const msg = _errorMsg( - `Block option must be supplied to compute blob gas price`, - vm, - block, - tx, - ) - throw new Error(msg) - } - blobGasPrice = opts.block.header.getBlobGasPrice() + blobGasPrice = opts.block?.header.getBlobGasPrice() ?? DEFAULT_HEADER.getBlobGasPrice() if (castTx.maxFeePerBlobGas < blobGasPrice) { const msg = _errorMsg( `Transaction's maxFeePerBlobGas ${castTx.maxFeePerBlobGas}) is less than block blobGasPrice (${blobGasPrice}).`, @@ -393,7 +382,7 @@ async function _runTx(vm: VM, opts: RunTxOpts): Promise { // EIP-1559 tx if (tx.supports(Capability.EIP1559FeeMarket)) { // TODO make txs use the new getEffectivePriorityFee - const baseFee = block.header.baseFeePerGas! + const baseFee = block?.header.baseFeePerGas ?? DEFAULT_HEADER.baseFeePerGas! inclusionFeePerGas = tx.getEffectivePriorityFee(baseFee) gasPrice = inclusionFeePerGas + baseFee @@ -401,7 +390,7 @@ async function _runTx(vm: VM, opts: RunTxOpts): Promise { // Have to cast as legacy tx since EIP1559 tx does not have gas price gasPrice = (tx).gasPrice if (vm.common.isActivatedEIP(1559)) { - const baseFee = block.header.baseFeePerGas! + const baseFee = block?.header.baseFeePerGas ?? DEFAULT_HEADER.baseFeePerGas! inclusionFeePerGas = (tx).gasPrice - baseFee } } @@ -588,9 +577,9 @@ async function _runTx(vm: VM, opts: RunTxOpts): Promise { // Update miner's balance let miner if (vm.common.consensusType() === ConsensusType.ProofOfAuthority) { - miner = cliqueSigner(block.header) + miner = cliqueSigner(block?.header ?? DEFAULT_HEADER) } else { - miner = block.header.coinbase + miner = block?.header.coinbase ?? DEFAULT_HEADER.coinbase } let minerAccount = await state.getAccount(miner) @@ -702,7 +691,10 @@ async function _runTx(vm: VM, opts: RunTxOpts): Promise { } // Generate the tx receipt - const gasUsed = opts.blockGasUsed !== undefined ? opts.blockGasUsed : block.header.gasUsed + const gasUsed = + opts.blockGasUsed !== undefined + ? opts.blockGasUsed + : (block?.header.gasUsed ?? DEFAULT_HEADER.gasUsed) const cumulativeGasUsed = gasUsed + results.totalGasSpent results.receipt = await generateTxReceipt( vm, @@ -834,8 +826,9 @@ export async function generateTxReceipt( * @param msg Base error message * @hidden */ -function _errorMsg(msg: string, vm: VM, block: Block, tx: TypedTransaction) { - const blockErrorStr = 'errorStr' in block ? block.errorStr() : 'block' +function _errorMsg(msg: string, vm: VM, block: Block | undefined, tx: TypedTransaction) { + const blockOrHeader = block ?? DEFAULT_HEADER + const blockErrorStr = 'errorStr' in blockOrHeader ? blockOrHeader.errorStr() : 'block' const txErrorStr = 'errorStr' in tx ? tx.errorStr() : 'tx' const errorMsg = `${msg} (${vm.errorStr()} -> ${blockErrorStr} -> ${txErrorStr})`