evm v0.1.2 EVM.MachineState

Module for tracking the current machine state, which is roughly equivilant to the VM state for an executing contract.

This is most often seen as µ in the Yellow Paper.

Link to this section Summary

Functions

Gets the program counter from a given machine state

After a memory operation, we may have incremented the total number of active words. This function takes a memory offset accessed and updates the machine state accordingly

Returns the next instruction to execute based on the current instruction. This may include a condition check (based on stack) to determine branching jump instruction

Sets the program counter for a given machine state

Returns a new execution environment less the amount of gas specified

Link to this section Types

Link to this type memory()
memory() :: binary
Link to this type pc()
pc() :: integer
Link to this type t()
t() :: %EVM.MachineState{active_words: integer, gas: EVM.Gas.t, memory: memory, pc: pc, stack: EVM.Stack.t}

Link to this section Functions

Link to this function get_pc(machine_state)
get_pc(EVM.MachineState.t) :: pc

Gets the program counter from a given machine state.

Examples

iex> EVM.MachineState.get_pc(%EVM.MachineState{pc: 5})
5
Link to this function maybe_set_active_words(machine_state, last_word)
maybe_set_active_words(t, EVM.val) :: t

After a memory operation, we may have incremented the total number of active words. This function takes a memory offset accessed and updates the machine state accordingly.

Examples

iex> %EVM.MachineState{active_words: 2} |> EVM.MachineState.maybe_set_active_words(1)
%EVM.MachineState{active_words: 2}

iex> %EVM.MachineState{active_words: 2} |> EVM.MachineState.maybe_set_active_words(3)
%EVM.MachineState{active_words: 3}
Link to this function next_pc(machine_state, exec_env)

Returns the next instruction to execute based on the current instruction. This may include a condition check (based on stack) to determine branching jump instruction.

Examples

iex> EVM.MachineState.next_pc(%EVM.MachineState{pc: 4, stack: [100]}, %EVM.ExecEnv{machine_code: EVM.MachineCode.compile([:push1, 3, :push1, 5, :add, :return])}) |> EVM.MachineState.get_pc() # standard add instruction
5

iex> EVM.MachineState.next_pc(%EVM.MachineState{pc: 0, stack: [100]}, %EVM.ExecEnv{machine_code: EVM.MachineCode.compile([:push1, 3, :push1, 5, :add, :return])}) |> EVM.MachineState.get_pc() # standard push1 instruction
2

iex> EVM.MachineState.next_pc(%EVM.MachineState{pc: 2, stack: [100]}, %EVM.ExecEnv{machine_code: EVM.MachineCode.compile([:push1, 3, :jump, :jumpdest, :return])}) |> EVM.MachineState.get_pc() # direct jump instruction
100

iex> EVM.MachineState.next_pc(%EVM.MachineState{pc: 1, stack: [100, 0]}, %EVM.ExecEnv{machine_code: EVM.MachineCode.compile([:push1, 3, :jumpi, :return])}) |> EVM.MachineState.get_pc() # branching jump instruction (fall-through)
2

iex> EVM.MachineState.next_pc(%EVM.MachineState{pc: 2, stack: [100, 1]}, %EVM.ExecEnv{machine_code: EVM.MachineCode.compile([:push1, 3, :jumpi, :return])}) |> EVM.MachineState.get_pc() # branching jump instruction (follow)
100

iex> EVM.MachineState.next_pc(%EVM.MachineState{pc: 0, stack: []}, %EVM.ExecEnv{machine_code: <<EVM.Instruction.encode(:jumpi)>>}) # branching jump instruction with no stack
** (FunctionClauseError) no function clause matching in EVM.Stack.pop_n/2
Link to this function set_pc(machine_state, pc)

Sets the program counter for a given machine state.

Examples

iex> EVM.MachineState.set_pc(%EVM.MachineState{pc: 5}, 10)
%EVM.MachineState{pc: 10}
Link to this function subtract_gas(exec_env, gas)
subtract_gas(t, EVM.Gas.t) :: t

Returns a new execution environment less the amount of gas specified.

Examples

iex> %EVM.MachineState{gas: 5} |> EVM.MachineState.subtract_gas(4)
%EVM.MachineState{gas: 1}

iex> %EVM.MachineState{gas: 5} |> EVM.MachineState.subtract_gas(6)
** (MatchError) no match of right hand side value: false