diff --git a/packages/common/src/eips.ts b/packages/common/src/eips.ts index 37335ba3c0..2e9fd42141 100644 --- a/packages/common/src/eips.ts +++ b/packages/common/src/eips.ts @@ -471,4 +471,17 @@ export const EIPs: EIPsDict = { minimumHardfork: Hardfork.London, requiredEIPs: [], }, + 7516: { + comment: 'BLOBBASEFEE opcode', + url: 'https://eips.ethereum.org/EIPS/eip-7516', + status: Status.Draft, + minimumHardfork: Hardfork.Paris, + requiredEIPs: [4844], + gasPrices: { + blobbasefee: { + v: 2, + d: 'Gas cost of the BLOBBASEFEE opcode', + }, + }, + }, } diff --git a/packages/common/src/hardforks.ts b/packages/common/src/hardforks.ts index 87255a28e6..a3c0267411 100644 --- a/packages/common/src/hardforks.ts +++ b/packages/common/src/hardforks.ts @@ -834,9 +834,9 @@ export const hardforks: HardforksDict = { cancun: { name: 'cancun', comment: - 'Next feature hardfork after the shanghai having proto-danksharding EIP 4844 blobs (still WIP hence not for production use), transient storage opcodes, parent beacon block root availability in EVM and selfdestruct only in same transaction', + 'Next feature hardfork after shanghai, includes proto-danksharding EIP 4844 blobs (still WIP hence not for production use), transient storage opcodes, parent beacon block root availability in EVM, selfdestruct only in same transaction, and blob base fee opcode', url: 'https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/cancun.md', status: Status.Final, - eips: [1153, 4844, 4788, 5656, 6780], + eips: [1153, 4844, 4788, 5656, 6780, 7516], }, } diff --git a/packages/evm/src/evm.ts b/packages/evm/src/evm.ts index 72713b71ed..10416990d6 100644 --- a/packages/evm/src/evm.ts +++ b/packages/evm/src/evm.ts @@ -162,7 +162,7 @@ export class EVM implements EVMInterface { // Supported EIPs const supportedEIPs = [ 1153, 1559, 2315, 2565, 2718, 2929, 2930, 3074, 3198, 3529, 3540, 3541, 3607, 3651, 3670, - 3855, 3860, 4399, 4895, 4788, 4844, 5133, 5656, 6780, + 3855, 3860, 4399, 4895, 4788, 4844, 5133, 5656, 6780, 7516, ] for (const eip of this.common.eips()) { @@ -966,7 +966,7 @@ export function EvmErrorResult(error: EvmError, gasUsed: bigint): ExecResult { } } -function defaultBlock(): Block { +export function defaultBlock(): Block { return { header: { number: BigInt(0), @@ -977,6 +977,7 @@ function defaultBlock(): Block { prevRandao: zeros(32), gasLimit: BigInt(0), baseFeePerGas: undefined, + getBlobGasPrice: () => undefined, }, } } diff --git a/packages/evm/src/interpreter.ts b/packages/evm/src/interpreter.ts index 77955225d5..6c248d4f6e 100644 --- a/packages/evm/src/interpreter.ts +++ b/packages/evm/src/interpreter.ts @@ -760,6 +760,18 @@ export class Interpreter { return baseFee } + /** + * Returns the Blob Base Fee of the block as proposed in [EIP-7516](https;//eips.etheruem.org/EIPS/eip-7516) + */ + getBlobBaseFee(): bigint { + const blobBaseFee = this._env.block.header.getBlobGasPrice() + if (blobBaseFee === undefined) { + // Sanity check + throw new Error('Block has no Blob Base Fee') + } + return blobBaseFee + } + /** * Returns the chain ID for current chain. Introduced for the * CHAINID opcode proposed in [EIP-1344](https://eips.ethereum.org/EIPS/eip-1344). diff --git a/packages/evm/src/opcodes/codes.ts b/packages/evm/src/opcodes/codes.ts index cc5d408717..97a6a48747 100644 --- a/packages/evm/src/opcodes/codes.ts +++ b/packages/evm/src/opcodes/codes.ts @@ -313,6 +313,12 @@ const eipOpcodes: { eip: number; opcodes: OpcodeEntry }[] = [ 0x5e: { name: 'MCOPY', isAsync: false, dynamicGas: true }, }, }, + { + eip: 7516, + opcodes: { + 0x4a: { name: 'BLOBBASEFEE', isAsync: false, dynamicGas: false }, + }, + }, ] /** diff --git a/packages/evm/src/opcodes/functions.ts b/packages/evm/src/opcodes/functions.ts index 0066f5eb15..590d4e3ea2 100644 --- a/packages/evm/src/opcodes/functions.ts +++ b/packages/evm/src/opcodes/functions.ts @@ -650,6 +650,13 @@ export const handlers: Map = new Map([ } }, ], + // 0x4a: BLOBBASEFEE + [ + 0x4a, + function (runState) { + runState.stack.push(runState.interpreter.getBlobBaseFee()) + }, + ], // 0x50 range - 'storage' and execution // 0x50: POP [ diff --git a/packages/evm/src/types.ts b/packages/evm/src/types.ts index 40926c3b5d..ef040f0275 100644 --- a/packages/evm/src/types.ts +++ b/packages/evm/src/types.ts @@ -338,6 +338,7 @@ export type Block = { prevRandao: Uint8Array gasLimit: bigint baseFeePerGas?: bigint + getBlobGasPrice(): bigint | undefined } } diff --git a/packages/evm/test/runCall.spec.ts b/packages/evm/test/runCall.spec.ts index bb04f0b451..c1c75060f3 100644 --- a/packages/evm/test/runCall.spec.ts +++ b/packages/evm/test/runCall.spec.ts @@ -3,6 +3,7 @@ import { Account, Address, MAX_UINT64, + bytesToBigInt, bytesToHex, concatBytes, hexToBytes, @@ -13,6 +14,7 @@ import { keccak256 } from 'ethereum-cryptography/keccak.js' import { assert, describe, it } from 'vitest' import * as genesisJSON from '../../client/test/testdata/geth-genesis/eip4844.json' +import { defaultBlock } from '../src/evm.js' import { ERROR } from '../src/exceptions.js' import { EVM } from '../src/index.js' @@ -602,6 +604,42 @@ describe('RunCall tests', () => { ) }) + it('runCall() => use BLOBBASEFEE opcode from EIP 7516', async () => { + // setup the evm + const common = Common.fromGethGenesis(genesisJSON, { + chain: 'custom', + hardfork: Hardfork.Cancun, + }) + const evm = new EVM({ + common, + }) + + const BLOBBASEFEE_OPCODE = 0x4a + assert.equal( + evm.getActiveOpcodes().get(BLOBBASEFEE_OPCODE)!.name, + 'BLOBBASEFEE', + 'Opcode 0x4a named BLOBBASEFEE' + ) + + const block = defaultBlock() + block.header.getBlobGasPrice = () => BigInt(119) + + // setup the call arguments + const runCallArgs: EVMRunCallOpts = { + gasLimit: BigInt(0xffffffffff), + // calldata -- retrieves the blobgas and returns it from memory + data: hexToBytes('0x4a60005260206000F3'), + block, + } + const res = await evm.runCall(runCallArgs) + assert.equal( + bytesToBigInt(unpadBytes(res.execResult.returnValue)), + BigInt(119), + 'retrieved correct gas fee' + ) + assert.equal(res.execResult.executionGasUsed, BigInt(6417), 'correct blob gas fee (2) charged') + }) + it('step event: ensure EVM memory and not internal memory gets reported', async () => { const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Berlin }) const evm = new EVM({