1
- import { cliqueSigner , createEmptyBlock } from '@ethereumjs/block'
1
+ import { cliqueSigner , createBlockHeader } from '@ethereumjs/block'
2
2
import { ConsensusType , Hardfork } from '@ethereumjs/common'
3
3
import { RLP } from '@ethereumjs/rlp'
4
4
import { Blob4844Tx , Capability , isBlob4844Tx } from '@ethereumjs/tx'
@@ -51,6 +51,8 @@ import type {
51
51
const debug = debugDefault ( 'vm:tx' )
52
52
const debugGas = debugDefault ( 'vm:tx:gas' )
53
53
54
+ const DEFAULT_HEADER = createBlockHeader ( )
55
+
54
56
let enableProfiler = false
55
57
const initLabel = 'EVM journal init, address/slot warming, fee validation'
56
58
const balanceNonceLabel = 'Balance/Nonce checks and update'
@@ -80,10 +82,7 @@ export async function runTx(vm: VM, opts: RunTxOpts): Promise<RunTxResult> {
80
82
console . time ( entireTxLabel )
81
83
}
82
84
83
- // create a reasonable default if no block is given
84
- opts . block = opts . block ?? createEmptyBlock ( { } , { common : vm . common } )
85
-
86
- if ( opts . skipHardForkValidation !== true ) {
85
+ if ( opts . skipHardForkValidation !== true && opts . block !== undefined ) {
87
86
// If block and tx don't have a same hardfork, set tx hardfork to block
88
87
if ( opts . tx . common . hardfork ( ) !== opts . block . common . hardfork ( ) ) {
89
88
opts . tx . common . setHardfork ( opts . block . common . hardfork ( ) )
@@ -95,7 +94,8 @@ export async function runTx(vm: VM, opts: RunTxOpts): Promise<RunTxResult> {
95
94
}
96
95
}
97
96
98
- if ( opts . skipBlockGasLimitValidation !== true && opts . block . header . gasLimit < opts . tx . gasLimit ) {
97
+ const gasLimit = opts . block ?. header . gasLimit ?? DEFAULT_HEADER . gasLimit
98
+ if ( opts . skipBlockGasLimitValidation !== true && gasLimit < opts . tx . gasLimit ) {
99
99
const msg = _errorMsg ( 'tx has a higher gas limit than the block' , vm , opts . block , opts . tx )
100
100
throw new Error ( msg )
101
101
}
@@ -198,10 +198,6 @@ async function _runTx(vm: VM, opts: RunTxOpts): Promise<RunTxResult> {
198
198
199
199
const { tx, block } = opts
200
200
201
- if ( ! block ) {
202
- throw new Error ( 'block required' )
203
- }
204
-
205
201
/**
206
202
* The `beforeTx` event
207
203
*
@@ -232,7 +228,8 @@ async function _runTx(vm: VM, opts: RunTxOpts): Promise<RunTxResult> {
232
228
vm . evm . journal . addAlwaysWarmAddress ( bytesToUnprefixedHex ( tx . to . bytes ) )
233
229
}
234
230
if ( vm . common . isActivatedEIP ( 3651 ) ) {
235
- vm . evm . journal . addAlwaysWarmAddress ( bytesToUnprefixedHex ( block . header . coinbase . bytes ) )
231
+ const coinbase = block ?. header . coinbase . bytes ?? DEFAULT_HEADER . coinbase . bytes
232
+ vm . evm . journal . addAlwaysWarmAddress ( bytesToUnprefixedHex ( coinbase ) )
236
233
}
237
234
}
238
235
@@ -260,7 +257,7 @@ async function _runTx(vm: VM, opts: RunTxOpts): Promise<RunTxResult> {
260
257
// Ensure that the user was willing to at least pay the base fee
261
258
// assert transaction.max_fee_per_gas >= block.base_fee_per_gas
262
259
const maxFeePerGas = 'maxFeePerGas' in tx ? tx . maxFeePerGas : tx . gasPrice
263
- const baseFeePerGas = block . header . baseFeePerGas !
260
+ const baseFeePerGas = block ? .header . baseFeePerGas ?? DEFAULT_HEADER . baseFeePerGas !
264
261
if ( maxFeePerGas < baseFeePerGas ) {
265
262
const msg = _errorMsg (
266
263
`Transaction's ${
@@ -296,7 +293,8 @@ async function _runTx(vm: VM, opts: RunTxOpts): Promise<RunTxResult> {
296
293
}
297
294
298
295
// Check balance against upfront tx cost
299
- const upFrontCost = tx . getUpfrontCost ( block . header . baseFeePerGas )
296
+ const baseFeePerGas = block ?. header . baseFeePerGas ?? DEFAULT_HEADER . baseFeePerGas
297
+ const upFrontCost = tx . getUpfrontCost ( baseFeePerGas )
300
298
if ( balance < upFrontCost ) {
301
299
if ( opts . skipBalance === true && fromAccount . balance < upFrontCost ) {
302
300
if ( tx . supports ( Capability . EIP1559FeeMarket ) === false ) {
@@ -339,16 +337,7 @@ async function _runTx(vm: VM, opts: RunTxOpts): Promise<RunTxResult> {
339
337
maxCost += totalblobGas * castTx . maxFeePerBlobGas
340
338
341
339
// 4844 minimum blobGas price check
342
- if ( opts . block === undefined ) {
343
- const msg = _errorMsg (
344
- `Block option must be supplied to compute blob gas price` ,
345
- vm ,
346
- block ,
347
- tx ,
348
- )
349
- throw new Error ( msg )
350
- }
351
- blobGasPrice = opts . block . header . getBlobGasPrice ( )
340
+ blobGasPrice = opts . block ?. header . getBlobGasPrice ( ) ?? DEFAULT_HEADER . getBlobGasPrice ( )
352
341
if ( castTx . maxFeePerBlobGas < blobGasPrice ) {
353
342
const msg = _errorMsg (
354
343
`Transaction's maxFeePerBlobGas ${ castTx . maxFeePerBlobGas } ) is less than block blobGasPrice (${ blobGasPrice } ).` ,
@@ -393,15 +382,15 @@ async function _runTx(vm: VM, opts: RunTxOpts): Promise<RunTxResult> {
393
382
// EIP-1559 tx
394
383
if ( tx . supports ( Capability . EIP1559FeeMarket ) ) {
395
384
// TODO make txs use the new getEffectivePriorityFee
396
- const baseFee = block . header . baseFeePerGas !
385
+ const baseFee = block ? .header . baseFeePerGas ?? DEFAULT_HEADER . baseFeePerGas !
397
386
inclusionFeePerGas = tx . getEffectivePriorityFee ( baseFee )
398
387
399
388
gasPrice = inclusionFeePerGas + baseFee
400
389
} else {
401
390
// Have to cast as legacy tx since EIP1559 tx does not have gas price
402
391
gasPrice = ( < LegacyTx > tx ) . gasPrice
403
392
if ( vm . common . isActivatedEIP ( 1559 ) ) {
404
- const baseFee = block . header . baseFeePerGas !
393
+ const baseFee = block ? .header . baseFeePerGas ?? DEFAULT_HEADER . baseFeePerGas !
405
394
inclusionFeePerGas = ( < LegacyTx > tx ) . gasPrice - baseFee
406
395
}
407
396
}
@@ -588,9 +577,9 @@ async function _runTx(vm: VM, opts: RunTxOpts): Promise<RunTxResult> {
588
577
// Update miner's balance
589
578
let miner
590
579
if ( vm . common . consensusType ( ) === ConsensusType . ProofOfAuthority ) {
591
- miner = cliqueSigner ( block . header )
580
+ miner = cliqueSigner ( block ? .header ?? DEFAULT_HEADER )
592
581
} else {
593
- miner = block . header . coinbase
582
+ miner = block ? .header . coinbase ?? DEFAULT_HEADER . coinbase
594
583
}
595
584
596
585
let minerAccount = await state . getAccount ( miner )
@@ -702,7 +691,10 @@ async function _runTx(vm: VM, opts: RunTxOpts): Promise<RunTxResult> {
702
691
}
703
692
704
693
// Generate the tx receipt
705
- const gasUsed = opts . blockGasUsed !== undefined ? opts . blockGasUsed : block . header . gasUsed
694
+ const gasUsed =
695
+ opts . blockGasUsed !== undefined
696
+ ? opts . blockGasUsed
697
+ : ( block ?. header . gasUsed ?? DEFAULT_HEADER . gasUsed )
706
698
const cumulativeGasUsed = gasUsed + results . totalGasSpent
707
699
results . receipt = await generateTxReceipt (
708
700
vm ,
@@ -834,8 +826,9 @@ export async function generateTxReceipt(
834
826
* @param msg Base error message
835
827
* @hidden
836
828
*/
837
- function _errorMsg ( msg : string , vm : VM , block : Block , tx : TypedTransaction ) {
838
- const blockErrorStr = 'errorStr' in block ? block . errorStr ( ) : 'block'
829
+ function _errorMsg ( msg : string , vm : VM , block : Block | undefined , tx : TypedTransaction ) {
830
+ const blockOrHeader = block ?? DEFAULT_HEADER
831
+ const blockErrorStr = 'errorStr' in blockOrHeader ? blockOrHeader . errorStr ( ) : 'block'
839
832
const txErrorStr = 'errorStr' in tx ? tx . errorStr ( ) : 'tx'
840
833
841
834
const errorMsg = `${ msg } (${ vm . errorStr ( ) } -> ${ blockErrorStr } -> ${ txErrorStr } )`
0 commit comments