evm v0.1.1 EVM.Instruction

Code to handle encoding and decoding instructions from opcodes.

Link to this section Summary

Functions

Returns the given instruction for a given opcode

Returns the given opcode for an instruction

Returns the current instruction at a given program counter address

Merges the state from an opcode with the current environment

Returns metadata about a given instruction or opcode, or nil

Returns the next instruction position given a current position and the type of instruction. This is to bypass push operands

Executes a single instruction. This simply does the effects of the instruction itself, ignoring the rest of the actions of an instruction cycle. This will effect, for instance, the stack, but will not effect the gas, etc

Link to this section Types

Link to this type instruction()
instruction() :: atom
Link to this type opcode()
opcode() :: byte

Link to this section Functions

Link to this function decode(opcode)
decode(opcode) :: instruction | nil

Returns the given instruction for a given opcode.

Examples

iex> EVM.Instruction.decode(0x00)
:stop

iex> EVM.Instruction.decode(0x01)
:add

iex> EVM.Instruction.decode(0x02)
:mul

iex> EVM.Instruction.decode(0xffff)
nil
Link to this function encode(instruction)
encode(instruction) :: opcode | nil

Returns the given opcode for an instruction.

Examples

iex> EVM.Instruction.encode(:stop)
0x00

iex> EVM.Instruction.encode(:add)
0x01

iex> EVM.Instruction.encode(:mul)
0x02

iex> EVM.Instruction.encode(:salmon)
nil
Link to this function get_instruction_at(machine_code, pc)
get_instruction_at(EVM.MachineCode.t, EVM.MachineState.pc) :: opcode

Returns the current instruction at a given program counter address.

Examples

iex> EVM.Instruction.get_instruction_at(<<0x11, 0x01, 0x02>>, 0)
0x11

iex> EVM.Instruction.get_instruction_at(<<0x11, 0x01, 0x02>>, 1)
0x01

iex> EVM.Instruction.get_instruction_at(<<0x11, 0x01, 0x02>>, 2)
0x02

iex> EVM.Instruction.get_instruction_at(<<0x11, 0x01, 0x02>>, 3)
0x00

Merges the state from an opcode with the current environment

Examples

iex> EVM.Instruction.merge_state(:noop, :add, %{}, %EVM.MachineState{}, %EVM.SubState{}, %EVM.ExecEnv{})
{%{}, %EVM.MachineState{}, %EVM.SubState{}, %EVM.ExecEnv{}}

iex> EVM.Instruction.merge_state(:unimplemented, :blarg, %{}, %EVM.MachineState{}, %EVM.SubState{}, %EVM.ExecEnv{})
{%{}, %EVM.MachineState{}, %EVM.SubState{}, %EVM.ExecEnv{}}

iex> EVM.Instruction.merge_state(%{stack: [1, 2, 3]}, :add, %{}, %EVM.MachineState{}, %EVM.SubState{}, %EVM.ExecEnv{})
{%{}, %EVM.MachineState{stack: [1, 2, 3]}, %EVM.SubState{}, %EVM.ExecEnv{}}

iex> EVM.Instruction.merge_state(%{machine_state: %EVM.MachineState{stack: [1, 2, 3]}}, :add, %{}, %EVM.MachineState{}, %EVM.SubState{}, %EVM.ExecEnv{})
{%{}, %EVM.MachineState{stack: [1, 2, 3]}, %EVM.SubState{}, %EVM.ExecEnv{}}

iex> EVM.Instruction.merge_state(%{machine_state: %EVM.MachineState{}, sub_state: %EVM.SubState{refund: 5}}, :add, %{}, %EVM.MachineState{}, %EVM.SubState{}, %EVM.ExecEnv{})
{%{}, %EVM.MachineState{}, %EVM.SubState{refund: 5}, %EVM.ExecEnv{}}

iex> EVM.Instruction.merge_state(%{exec_env: %EVM.ExecEnv{stack_depth: 1}}, :add, %{}, %EVM.MachineState{}, %EVM.SubState{}, %EVM.ExecEnv{})
{%{}, %EVM.MachineState{}, %EVM.SubState{}, %EVM.ExecEnv{stack_depth: 1}}

iex> EVM.Instruction.merge_state(%{stack: [1, 2, 3], machine_state: %EVM.MachineState{pc: 5, stack: [4, 5]}}, :add, %{}, %EVM.MachineState{}, %EVM.SubState{}, %EVM.ExecEnv{})
{%{}, %EVM.MachineState{pc: 5, stack: [1, 2, 3]}, %EVM.SubState{}, %EVM.ExecEnv{}}

iex> EVM.Instruction.merge_state(%EVM.MachineState{pc: 5, stack: [4, 5]}, :add, %{}, %EVM.MachineState{}, %EVM.SubState{}, %EVM.ExecEnv{})
{%{}, %EVM.MachineState{pc: 5, stack: [4, 5]}, %EVM.SubState{}, %EVM.ExecEnv{}}
Link to this function metadata(instruction)

Returns metadata about a given instruction or opcode, or nil.

Examples

iex> EVM.Instruction.metadata(:stop)
%EVM.Instruction.Metadata{id: 0x00, sym: :stop, d: 0, a: 0, description: "Halts execution"}

iex> EVM.Instruction.metadata(0x00)
%EVM.Instruction.Metadata{id: 0x00, sym: :stop, d: 0, a: 0, description: "Halts execution"}

iex> EVM.Instruction.metadata(:add)
%EVM.Instruction.Metadata{id: 0x01, sym: :add, d: 2, a: 1, description: "Addition operation"}

iex> EVM.Instruction.metadata(:push1)
%EVM.Instruction.Metadata{id: 0x60, sym: :push1, fun: :push_n, args: [1], d: 0, a: 1, description: "Place 1-byte item on stack"}

iex> EVM.Instruction.metadata(0xfe)
nil

iex> EVM.Instruction.metadata(nil)
nil
Link to this function next_instr_pos(pos, instr)

Returns the next instruction position given a current position and the type of instruction. This is to bypass push operands.

Examples

iex> EVM.Instruction.next_instr_pos(10, :add)
11

iex> EVM.Instruction.next_instr_pos(20, :mul)
21

iex> EVM.Instruction.next_instr_pos(10, :push1)
12

iex> EVM.Instruction.next_instr_pos(10, :push32)
43
Link to this function run_instruction(instruction, state, machine_state, sub_state, exec_env)

Executes a single instruction. This simply does the effects of the instruction itself, ignoring the rest of the actions of an instruction cycle. This will effect, for instance, the stack, but will not effect the gas, etc.

Examples

# TODO: How to handle trie state in tests?

# Add
iex> EVM.Instruction.run_instruction(:add, %{}, %EVM.MachineState{stack: [1, 2]}, %EVM.SubState{}, %EVM.ExecEnv{})
{%{}, %EVM.MachineState{stack: [3]}, %EVM.SubState{}, %EVM.ExecEnv{}}

# Push
iex> EVM.Instruction.run_instruction(:push1, %{}, %EVM.MachineState{stack: [1, 2]}, %EVM.SubState{}, %EVM.ExecEnv{machine_code: <<00, 01>>})
{%{}, %EVM.MachineState{stack: [1, 1, 2]}, %EVM.SubState{}, %EVM.ExecEnv{machine_code: <<00, 01>>}}

# nil
iex> EVM.Instruction.run_instruction(:stop, %{}, %EVM.MachineState{stack: [1, 2]}, %EVM.SubState{}, %EVM.ExecEnv{})
{%{}, %EVM.MachineState{stack: [1, 2]}, %EVM.SubState{}, %EVM.ExecEnv{}}

# Unimplemented
iex> EVM.Instruction.run_instruction(:log0, %{}, %EVM.MachineState{stack: [1, 2]}, %EVM.SubState{}, %EVM.ExecEnv{})
{%{}, %EVM.MachineState{stack: []}, %EVM.SubState{}, %EVM.ExecEnv{}}