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

evm/vm: reintroduce evm interface #2869

Merged
merged 10 commits into from
Jul 11, 2023
3 changes: 2 additions & 1 deletion packages/evm/src/evm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import type {
Blockchain,
CustomOpcode,
EVMEvents,
EVMInterface,
EVMRunCallOpts,
EVMRunCodeOpts,
Log,
Expand Down Expand Up @@ -143,7 +144,7 @@ export interface EVMOpts {
* and storing them to state (or discarding changes in case of exceptions).
* @ignore
*/
export class EVM {
export class EVM implements EVMInterface {
protected static supportedHardforks = [
Hardfork.Chainstart,
Hardfork.Homestead,
Expand Down
25 changes: 24 additions & 1 deletion packages/evm/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import type { InterpreterStep } from './interpreter.js'
import type { Message } from './message.js'
import type { AsyncDynamicGasHandler, SyncDynamicGasHandler } from './opcodes/gas.js'
import type { OpHandler } from './opcodes/index.js'
import type { Address } from '@ethereumjs/util'
import type { PrecompileFunc } from './precompiles/types.js'
import type { EVMStateManagerInterface } from '@ethereumjs/common'
import type { Account, Address, AsyncEventEmitter } from '@ethereumjs/util'

export type DeleteOpcode = {
opcode: number
Expand Down Expand Up @@ -134,6 +136,27 @@ export type EVMEvents = {
step: (data: InterpreterStep, resolve?: (result?: any) => void) => void
}

export interface EVMInterface {
journal: {
commit(): Promise<void>
revert(): Promise<void>
checkpoint(): Promise<void>
cleanJournal(): void
cleanup(): Promise<void>
putAccount(address: Address, account: Account): Promise<void>
deleteAccount(address: Address): Promise<void>
accessList?: Map<string, Set<string>>
addAlwaysWarmAddress(address: string, addToAccessList?: boolean): void
addAlwaysWarmSlot(address: string, slot: string, addToAccessList?: boolean): void
reportAccessList(): void // TODO check this name, because it clears the internal access list and does not "report" it
// (access list will be reported if the access list map exists internally, defaults to undefined?)
}
stateManager: EVMStateManagerInterface
precompiles: Map<string, PrecompileFunc>
runCall(opts: EVMRunCallOpts): Promise<EVMResult>
events?: AsyncEventEmitter<EVMEvents>
gabrocheleau marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Log that the contract emits.
*/
Expand Down
10 changes: 7 additions & 3 deletions packages/vm/src/runBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import type {
TxReceipt,
} from './types.js'
import type { VM } from './vm.js'
import type { EVM } from '@ethereumjs/evm'
import type { EVMInterface } from '@ethereumjs/evm/dist/cjs/types.js' //TODO fix this import
const { debug: createDebugLogger } = debugDefault

const debug = createDebugLogger('vm:block')
Expand Down Expand Up @@ -404,7 +404,11 @@ export function calculateMinerReward(minerReward: bigint, ommersNum: number): bi
return reward
}

export async function rewardAccount(evm: EVM, address: Address, reward: bigint): Promise<Account> {
export async function rewardAccount(
evm: EVMInterface,
address: Address,
reward: bigint
): Promise<Account> {
let account = await evm.stateManager.getAccount(address)
if (account === undefined) {
account = new Account()
Expand Down Expand Up @@ -438,7 +442,7 @@ export function encodeReceipt(receipt: TxReceipt, txType: TransactionType) {
/**
* Apply the DAO fork changes to the VM
*/
async function _applyDAOHardfork(evm: EVM) {
async function _applyDAOHardfork(evm: EVMInterface) {
const state = evm.stateManager
const DAORefundContractAddress = new Address(unprefixedHexToBytes(DAORefundContract))
if ((await state.getAccount(DAORefundContractAddress)) === undefined) {
Expand Down
2 changes: 1 addition & 1 deletion packages/vm/src/runTx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export async function runTx(this: VM, opts: RunTxOpts): Promise<RunTxResult> {
await this.evm.journal.cleanup()

if (opts.reportAccessList === true) {
this.evm.journal.reportAccessList()
this.evm.journal.reportAccessList() // TODO this name is wrong (this clears the internal access list). (Can this be done in evm.journal.cleanJournal()?)
}

await this.evm.journal.checkpoint()
Expand Down
5 changes: 3 additions & 2 deletions packages/vm/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import type { Bloom } from './bloom/index.js'
import type { Block, BlockOptions, HeaderData } from '@ethereumjs/block'
import type { BlockchainInterface } from '@ethereumjs/blockchain'
import type { Common, EVMStateManagerInterface } from '@ethereumjs/common'
import type { EVM, EVMResult, Log } from '@ethereumjs/evm'
import type { EVMResult, Log } from '@ethereumjs/evm'
import type { EVMInterface } from '@ethereumjs/evm/dist/cjs/types.js' // TODO fix this import
import type { AccessList, TypedTransaction } from '@ethereumjs/tx'
import type { BigIntLike, GenesisState, WithdrawalData } from '@ethereumjs/util'
export type TxReceipt = PreByzantiumTxReceipt | PostByzantiumTxReceipt | EIP4844BlobTxReceipt
Expand Down Expand Up @@ -139,7 +140,7 @@ export interface VMOpts {
/**
* Use a custom EVM to run Messages on. If this is not present, use the default EVM.
*/
evm?: EVM
evm?: EVMInterface
}

/**
Expand Down
5 changes: 3 additions & 2 deletions packages/vm/src/vm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import type {
} from './types.js'
import type { BlockchainInterface } from '@ethereumjs/blockchain'
import type { EVMStateManagerInterface } from '@ethereumjs/common'
import type { EVMInterface } from '@ethereumjs/evm/dist/cjs/types.js'
Copy link
Member

Choose a reason for hiding this comment

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

These imports are still a total no-go for merging, I guess that's obvious?

Copy link
Member Author

Choose a reason for hiding this comment

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

Huh, how did this get introduced? 🤔 I think VSCode auto-imported this

Copy link
Member Author

Choose a reason for hiding this comment

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

Nvm see my new comment on the PR, PR was not yet ready to be reviewed (sorry for marking it as ready-to-review)

import type { BigIntLike, GenesisState } from '@ethereumjs/util'

/**
Expand All @@ -45,7 +46,7 @@ export class VM {
/**
* The EVM used for bytecode execution
*/
readonly evm: EVM
readonly evm: EVMInterface

protected readonly _opts: VMOpts
protected _isInitialized: boolean = false
Expand Down Expand Up @@ -231,7 +232,7 @@ export class VM {
blockchain,
stateManager,
}
const evmCopy = new EVM(evmOpts)
const evmCopy = new EVM(evmOpts) // TODO fixme (should copy the EVMInterface, not default EVM)
gabrocheleau marked this conversation as resolved.
Show resolved Hide resolved
return VM.create({
stateManager,
blockchain: this.blockchain,
Expand Down
4 changes: 2 additions & 2 deletions packages/vm/test/tester/runners/GeneralStateTestsRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ async function runTestCase(options: any, testData: any, t: tape.Test) {
const block = makeBlockFromEnv(testData.env, { common })

if (options.jsontrace === true) {
vm.evm.events.on('step', stepHandler)
vm.evm.events!.on('step', stepHandler)
gabrocheleau marked this conversation as resolved.
Show resolved Hide resolved
vm.events.on('afterTx', afterTxHandler)
}
try {
Expand All @@ -156,7 +156,7 @@ async function runTestCase(options: any, testData: any, t: tape.Test) {

t.ok(stateRootsAreEqual, `[ ${timeSpent} ] the state roots should match (${execInfo})`)

vm.evm.events.removeListener('step', stepHandler)
vm.evm.events!.removeListener('step', stepHandler)
vm.events.removeListener('afterTx', afterTxHandler)

// @ts-ignore Explicitly delete objects for memory optimization (early GC)
Expand Down