Skip to content

Commit

Permalink
Refactor ExecutionResult (#48)
Browse files Browse the repository at this point in the history
* Reorganize files

* Simplify ExecutionResult

* Make ExecutionResult a discriminated union

* Reduce Memory to a single class

* Make parseBytecode easier to read
  • Loading branch information
sz-piotr authored Feb 2, 2020
1 parent 3673b4f commit 92697eb
Show file tree
Hide file tree
Showing 116 changed files with 329 additions and 694 deletions.
3 changes: 2 additions & 1 deletion packages/evm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
},
"dependencies": {
"@types/bn.js": "^4.11.5",
"bn.js": "^5.1.1"
"bn.js": "^5.1.1",
"js-sha3": "^0.8.0"
},
"devDependencies": {
"@types/chai": "^4.2.7",
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Stack } from './Stack'
import { OutOfGas } from './errors'
import { Memory, GasAwareMemory } from './Memory'
import { Memory } from './Memory'
import { State } from './State'
import { Byte } from './Byte'
import { Message } from './Message'
Expand All @@ -10,22 +10,17 @@ import { parseBytecode } from './parseBytecode'
export class ExecutionContext {
code: Opcode[]
stack = new Stack()
memory: GasAwareMemory
state: State
memory: Memory
returnValue?: Byte[]
reverted = false
programCounter = 0

private _gasUsed = 0
private _gasRefund = 0

constructor (public message: Message) {
this.state = message.state.clone()
constructor (public message: Message, public state: State) {
this.code = parseBytecode(message.code)
this.memory = new GasAwareMemory(
new Memory(),
this.useGas.bind(this),
)
this.memory = new Memory(this.useGas.bind(this))
}

get gasUsed () {
Expand All @@ -40,10 +35,6 @@ export class ExecutionContext {
}
}

useRemainingGas () {
this._gasUsed = this.message.gasLimit
}

get gasRefund () {
return this._gasRefund
}
Expand Down
27 changes: 27 additions & 0 deletions packages/evm/src/ExecutionResult.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { State } from './State'
import { Byte } from './Byte'
import { VMError } from './errors'

export type ExecutionResult =
| ExecutionSuccess
| ExecutionRevert
| ExecutionError

export interface ExecutionSuccess {
type: 'ExecutionSuccess',
state: State,
gasUsed: number,
gasRefund: number,
returnValue: Byte[],
}

export interface ExecutionRevert {
type: 'ExecutionRevert',
gasUsed: number,
returnValue: Byte[],
}

export interface ExecutionError {
type: 'ExecutionError',
error: VMError,
}
76 changes: 27 additions & 49 deletions packages/evm/src/evm/Memory.ts → packages/evm/src/Memory.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,38 @@
import { GasCost } from './opcodes'
import { Byte } from './Byte'

export interface IMemory {
getSize (): number,
getBytes (offset: number, length: number): Byte[],
setBytes (offset: number, bytes: Byte[]): void,
}
export class Memory {
private items: Byte[] = []
private memoryUsed = 0
private gasUsed = 0

export class GasAwareMemory implements IMemory {
constructor (
public memory: Memory,
private useGas: (gas: number) => void,
) {}

private memoryUsed = 0
private gasUsed = 0
getSize () {
return this.items.length
}

getBytes (offset: number, length: number) {
this.onMemoryAccess(offset, length)
if (length === 0) {
return []
}
this.expand(offset + length)
return this.items.slice(offset, offset + length)
}

setBytes (offset: number, bytes: Byte[]) {
this.onMemoryAccess(offset, bytes.length)
if (bytes.length === 0) {
return
}
this.expand(offset + bytes.length)
for (let i = 0; i < bytes.length; i++) {
this.items[offset + i] = bytes[i]
}
}

private onMemoryAccess (offset: number, length: number) {
if (length === 0) {
Expand All @@ -31,50 +49,10 @@ export class GasAwareMemory implements IMemory {
}
}

getSize () {
return this.memory.getSize()
}

getBytes (offset: number, length: number) {
this.onMemoryAccess(offset, length)
return this.memory.getBytes(offset, length)
}

setBytes (offset: number, bytes: Byte[]) {
this.onMemoryAccess(offset, bytes.length)
this.memory.setBytes(offset, bytes)
}
}

export class Memory implements IMemory {
private items: Byte[] = []

private expand (targetSize: number) {
const targetLength = 32 * Math.ceil(targetSize / 32)
for (let i = this.items.length; i < targetLength; i++) {
this.items[i] = 0 as Byte
}
}

getSize () {
return this.items.length
}

getBytes (offset: number, length: number) {
if (length === 0) {
return []
}
this.expand(offset + length)
return this.items.slice(offset, offset + length)
}

setBytes (offset: number, bytes: Byte[]) {
if (bytes.length === 0) {
return
}
this.expand(offset + bytes.length)
for (let i = 0; i < bytes.length; i++) {
this.items[offset + i] = bytes[i]
}
}
}
16 changes: 16 additions & 0 deletions packages/evm/src/Message.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Address } from './Address'
import { Bytes32 } from './Bytes32'
import { Byte } from './Byte'

export interface Message {
readonly account: Address,
readonly code: readonly Byte[],
readonly data: readonly Byte[],
readonly origin: Address,
readonly sender: Address,
readonly gasLimit: number,
readonly gasPrice: Bytes32,
readonly value: Bytes32,
readonly enableStateModifications: boolean,
readonly callDepth: number,
}
File renamed without changes.
File renamed without changes.
31 changes: 0 additions & 31 deletions packages/evm/src/cloneBlock.ts

This file was deleted.

16 changes: 0 additions & 16 deletions packages/evm/src/createBlock.ts

This file was deleted.

28 changes: 0 additions & 28 deletions packages/evm/src/createGenesisBlock.ts

This file was deleted.

File renamed without changes.
18 changes: 0 additions & 18 deletions packages/evm/src/evm/Message.ts

This file was deleted.

53 changes: 0 additions & 53 deletions packages/evm/src/evm/executeCode.ts

This file was deleted.

44 changes: 44 additions & 0 deletions packages/evm/src/executeCode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { ExecutionContext } from './ExecutionContext'
import { Message } from './Message'
import { opSTOP } from './opcodes/control'
import { VMError } from './errors'
import { ExecutionResult } from './ExecutionResult'
import { State } from './State'

export function executeCode (message: Message, state: State): ExecutionResult {
const ctx = new ExecutionContext(message, state)

while (ctx.returnValue === undefined) {
const opcode = ctx.code[ctx.programCounter] || opSTOP
ctx.programCounter++
try {
opcode(ctx)
} catch (error) {
if (error instanceof VMError) {
return {
type: 'ExecutionError',
error,
}
} else {
// programmer error
throw error
}
}
}

if (ctx.reverted) {
return {
type: 'ExecutionRevert',
gasUsed: ctx.gasUsed,
returnValue: ctx.returnValue,
}
} else {
return {
type: 'ExecutionSuccess',
gasUsed: ctx.gasUsed,
gasRefund: ctx.gasRefund,
returnValue: ctx.returnValue,
state: ctx.state,
}
}
}
Loading

0 comments on commit 92697eb

Please sign in to comment.