Skip to content

Commit

Permalink
EVM Types Cleanup (#2001)
Browse files Browse the repository at this point in the history
* EVM: reorder types, add some code docs

* EVM: do not export the the replicated intermediary state interfaces, only the resulting dedicated VmStateAccess interface

* EVM: rename VmStateAccess -> EVMStateAccess

* EVM: rename RunCallOpts -> EVMRunCallOpts, RunCodeOpts -> EVMRunCodeOpts interfaces to have these more prominently stand out

* EVM: removed/internalized TxContext interface

* EVM: localized NewContractEvent type

* EVM: simplified test command (removed test:API), moved test files one level up

* EVM: fixed test import references

* EVM: moved all result types to file bottom
  • Loading branch information
holgerd77 authored Jun 28, 2022
1 parent c06d9db commit 5bcd389
Show file tree
Hide file tree
Showing 20 changed files with 288 additions and 265 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/node-versions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ jobs:
run: npm run test
working-directory: packages/ethash
if: ${{ matrix.node >= 14 }}

- name: Test EVM
run: npm run test
working-directory: packages/evm
if: ${{ matrix.node >= 14 }}

- name: Test Trie
run: npm run test
Expand Down
7 changes: 3 additions & 4 deletions packages/evm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,11 @@
"prepublishOnly": "../../config/cli/prepublish.sh && npm run test:buildIntegrity",
"clean": "../../config/cli/clean-package.sh",
"coverage": "nyc npm run coverage:test",
"coverage:test": "npm run test:API",
"coverage:test": "npm run test",
"docs:build": "typedoc --options typedoc.js",
"tape": "tape -r ts-node/register --stack-size=1500",
"test:API": "npm run tape -- './tests/api/**/*.spec.ts'",
"test:API:browser": "karma start karma.conf.js",
"test": "echo \"[INFO] Generic test cmd not used. See package.json for more specific test run cmds.\"",
"test": "npm run tape -- './tests/**/*.spec.ts'",
"test:browser": "karma start karma.conf.js",
"lint": "../../config/cli/lint.sh",
"lint:fix": "../../config/cli/lint-fix.sh",
"formatTest": "node ./scripts/formatTest",
Expand Down
230 changes: 113 additions & 117 deletions packages/evm/src/evm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ import {
/*ExternalInterface,*/
/*ExternalInterfaceFactory,*/
Log,
RunCallOpts,
RunCodeOpts,
TxContext,
EVMRunCallOpts,
EVMRunCodeOpts,
} from './types'
import { EEIInterface } from './types'
import TransientStorage from './transientStorage'
Expand Down Expand Up @@ -126,124 +125,17 @@ export interface EVMOpts {
eei: EEIInterface
}

/**
* Result of executing a message via the {@link EVM}.
*/
export interface EVMResult {
/**
* Address of created account during transaction, if any
*/
createdAddress?: Address
/**
* Contains the results from running the code, if any, as described in {@link runCode}
*/
execResult: ExecResult
}

/**
* Result of executing a call via the {@link EVM}.
*/
export interface ExecResult {
runState?: RunState
/**
* Description of the exception, if any occurred
*/
exceptionError?: EvmError
/**
* Amount of gas left
*/
gas?: bigint
/**
* Amount of gas the code used to run
*/
executionGasUsed: bigint
/**
* Return value from the contract
*/
returnValue: Buffer
/**
* Array of logs that the contract emitted
*/
logs?: Log[]
/**
* A map from the accounts that have self-destructed to the addresses to send their funds to
*/
selfdestruct?: { [k: string]: Buffer }
/**
* The gas refund counter
*/
gasRefund?: bigint
}

export interface NewContractEvent {
address: Address
// The deployment code
code: Buffer
}

export function OOGResult(gasLimit: bigint): ExecResult {
return {
returnValue: Buffer.alloc(0),
executionGasUsed: gasLimit,
exceptionError: new EvmError(ERROR.OUT_OF_GAS),
}
}
// CodeDeposit OOG Result
export function COOGResult(gasUsedCreateCode: bigint): ExecResult {
return {
returnValue: Buffer.alloc(0),
executionGasUsed: gasUsedCreateCode,
exceptionError: new EvmError(ERROR.CODESTORE_OUT_OF_GAS),
}
}

export function INVALID_BYTECODE_RESULT(gasLimit: bigint): ExecResult {
return {
returnValue: Buffer.alloc(0),
executionGasUsed: gasLimit,
exceptionError: new EvmError(ERROR.INVALID_BYTECODE_RESULT),
}
}

export function INVALID_EOF_RESULT(gasLimit: bigint): ExecResult {
return {
returnValue: Buffer.alloc(0),
executionGasUsed: gasLimit,
exceptionError: new EvmError(ERROR.INVALID_EOF_FORMAT),
}
}

export function EvmErrorResult(error: EvmError, gasUsed: bigint): ExecResult {
return {
returnValue: Buffer.alloc(0),
executionGasUsed: gasUsed,
exceptionError: error,
}
}

function defaultBlock(): Block {
return {
header: {
number: BigInt(0),
cliqueSigner: () => Address.zero(),
coinbase: Address.zero(),
timestamp: BigInt(0),
difficulty: BigInt(0),
prevRandao: zeros(32),
gasLimit: BigInt(0),
baseFeePerGas: undefined,
},
}
}

/**
* EVM is responsible for executing an EVM message fully
* (including any nested calls and creates), processing the results
* and storing them to state (or discarding changes in case of exceptions).
* @ignore
*/
export default class EVM extends AsyncEventEmitter<EVMEvents> implements EVMInterface {
protected _tx?: TxContext
protected _tx?: {
gasPrice: bigint
origin: Address
}
protected _block?: Block

readonly _common: Common
Expand Down Expand Up @@ -533,7 +425,7 @@ export default class EVM extends AsyncEventEmitter<EVMEvents> implements EVMInte

await this.eei.state.clearContractStorage(message.to)

const newContractEvent: NewContractEvent = {
const newContractEvent = {
address: message.to,
code: message.code,
}
Expand Down Expand Up @@ -758,7 +650,7 @@ export default class EVM extends AsyncEventEmitter<EVMEvents> implements EVMInte
* based on the `to` address. It checkpoints the state and reverts changes
* if an exception happens during the message execution.
*/
async runCall(opts: RunCallOpts): Promise<EVMResult> {
async runCall(opts: EVMRunCallOpts): Promise<EVMResult> {
let message = opts.message
if (!message) {
this._block = opts.block ?? defaultBlock()
Expand Down Expand Up @@ -874,7 +766,7 @@ export default class EVM extends AsyncEventEmitter<EVMEvents> implements EVMInte
* Bound to the global VM and therefore
* shouldn't be used directly from the evm class
*/
async runCode(opts: RunCodeOpts): Promise<ExecResult> {
async runCode(opts: EVMRunCodeOpts): Promise<ExecResult> {
this._block = opts.block ?? defaultBlock()

this._tx = {
Expand Down Expand Up @@ -999,3 +891,107 @@ export default class EVM extends AsyncEventEmitter<EVMEvents> implements EVMInte
return new EVM(opts)
}
}

/**
* Result of executing a message via the {@link EVM}.
*/
export interface EVMResult {
/**
* Address of created account during transaction, if any
*/
createdAddress?: Address
/**
* Contains the results from running the code, if any, as described in {@link runCode}
*/
execResult: ExecResult
}

/**
* Result of executing a call via the {@link EVM}.
*/
export interface ExecResult {
runState?: RunState
/**
* Description of the exception, if any occurred
*/
exceptionError?: EvmError
/**
* Amount of gas left
*/
gas?: bigint
/**
* Amount of gas the code used to run
*/
executionGasUsed: bigint
/**
* Return value from the contract
*/
returnValue: Buffer
/**
* Array of logs that the contract emitted
*/
logs?: Log[]
/**
* A map from the accounts that have self-destructed to the addresses to send their funds to
*/
selfdestruct?: { [k: string]: Buffer }
/**
* The gas refund counter
*/
gasRefund?: bigint
}

export function OOGResult(gasLimit: bigint): ExecResult {
return {
returnValue: Buffer.alloc(0),
executionGasUsed: gasLimit,
exceptionError: new EvmError(ERROR.OUT_OF_GAS),
}
}
// CodeDeposit OOG Result
export function COOGResult(gasUsedCreateCode: bigint): ExecResult {
return {
returnValue: Buffer.alloc(0),
executionGasUsed: gasUsedCreateCode,
exceptionError: new EvmError(ERROR.CODESTORE_OUT_OF_GAS),
}
}

export function INVALID_BYTECODE_RESULT(gasLimit: bigint): ExecResult {
return {
returnValue: Buffer.alloc(0),
executionGasUsed: gasLimit,
exceptionError: new EvmError(ERROR.INVALID_BYTECODE_RESULT),
}
}

export function INVALID_EOF_RESULT(gasLimit: bigint): ExecResult {
return {
returnValue: Buffer.alloc(0),
executionGasUsed: gasLimit,
exceptionError: new EvmError(ERROR.INVALID_EOF_FORMAT),
}
}

export function EvmErrorResult(error: EvmError, gasUsed: bigint): ExecResult {
return {
returnValue: Buffer.alloc(0),
executionGasUsed: gasUsed,
exceptionError: error,
}
}

function defaultBlock(): Block {
return {
header: {
number: BigInt(0),
cliqueSigner: () => Address.zero(),
coinbase: Address.zero(),
timestamp: BigInt(0),
difficulty: BigInt(0),
prevRandao: zeros(32),
gasLimit: BigInt(0),
baseFeePerGas: undefined,
},
}
}
12 changes: 10 additions & 2 deletions packages/evm/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import { getActivePrecompiles } from './precompiles'
import { EEIInterface, EVMInterface, VmStateAccess, Log } from './types'
import { EEIInterface, EVMInterface, EVMStateAccess, Log } from './types'
import EVM, { EVMResult } from './evm'
import { EvmError } from './exceptions'

export { getActivePrecompiles, EEIInterface, EVMInterface, EvmError, VmStateAccess, Log, EVMResult }
export {
getActivePrecompiles,
EEIInterface,
EVMInterface,
EvmError,
EVMStateAccess,
Log,
EVMResult,
}

export default EVM
6 changes: 3 additions & 3 deletions packages/evm/src/interpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import Common, { ConsensusAlgorithm } from '@ethereumjs/common'
import EVM, { EVMResult } from './evm'
import Message from './message'
import { Log } from './types'
import { EEIInterface, VmStateAccess, Block } from './types'
import { EEIInterface, EVMStateAccess, Block } from './types'

const debugGas = createDebugLogger('vm:eei:gas')

Expand Down Expand Up @@ -64,7 +64,7 @@ export interface RunState {
code: Buffer
shouldDoJumpAnalysis: boolean
validJumps: Uint8Array // array of values where validJumps[index] has value 0 (default), 1 (jumpdest), 2 (beginsub)
vmState: VmStateAccess
vmState: EVMStateAccess
eei: EEIInterface
env: Env
messageGasLimit?: bigint // Cache value from `gas.ts` to save gas limit for a message call
Expand All @@ -83,7 +83,7 @@ export interface InterpreterResult {
export interface InterpreterStep {
gasLeft: bigint
gasRefund: bigint
vmState: VmStateAccess
vmState: EVMStateAccess
stack: bigint[]
returnStack: bigint[]
pc: number
Expand Down
Loading

0 comments on commit 5bcd389

Please sign in to comment.