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 section Functions
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
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
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{}}
metadata(instruction | opcode) :: EVM.Instruction.Metadata.t | nil
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
next_instr_pos(EVM.MachineState.pc, instruction) :: EVM.MachineState.pc
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
run_instruction(instruction, EVM.state, EVM.MachineState.t, EVM.SubState.t, EVM.ExecEnv.t) :: {EVM.state, EVM.MachineState.t, EVM.SubState.t, EVM.ExecEnv.t}
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{}}