Skip to content

Commit

Permalink
Merge pull request #45 from poanetwork/log_operations
Browse files Browse the repository at this point in the history
log operations
  • Loading branch information
ayrat555 authored May 1, 2018
2 parents f550212 + 6522865 commit 56890e6
Show file tree
Hide file tree
Showing 14 changed files with 389 additions and 62 deletions.
1 change: 1 addition & 0 deletions .dialyzer.ignore-warnings
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ lib/evm/interface/mock/mock_account_interface.ex:138: The inferred return type o
lib/evm/interface/mock/mock_account_interface.ex:199: The return type {integer(),atom(),#{'__struct__':='Elixir.EVM.SubState', 'logs':=binary(), 'refund':=integer(), 'suicide_list':=[<<_:160>>]}} in the specification of create_contract/9 is not a subtype of {atom(),integer(),#{'__struct__':='Elixir.EVM.SubState', 'logs':=binary(), 'refund':=integer(), 'suicide_list':=[<<_:160>>]}}, which is the expected return type for the callback of the 'Elixir.EVM.Interface.AccountInterface' behaviour
lib/evm/interface/mock/mock_account_interface.ex:199: Invalid type specification for function 'Elixir.EVM.Interface.AccountInterface.EVM.Interface.Mock.MockAccountInterface':create_contract/9. The success typing is (atom() | #{'contract_result':='nil' | [{atom(),_}] | map(), _=>_},_,_,_,_,_,_,_,_) -> {atom() | #{'contract_result':='nil' | [{_,_}] | map(), _=>_},_,_}
lib/evm/interface/mock/mock_block_interface.ex:10: Invalid type specification for function 'Elixir.EVM.Interface.Mock.MockBlockInterface':new/2. The success typing is (_,_) -> #{'__struct__':='Elixir.EVM.Interface.Mock.MockBlockInterface', 'block_header':=_, 'block_map':=_}
lib/evm/interface/mock/mock_account_interface.ex:199: The return type {integer(),atom(),#{'__struct__':='Elixir.EVM.SubState', 'logs':=[#{'__struct__':='Elixir.EVM.LogEntry', 'address':=<<_:160>>, 'data':=binary(), 'topics':=[binary()]}], 'refund':=integer(), 'suicide_list':=[<<_:160>>]}} in the specification of create_contract/9 is not a subtype of {atom(),integer(),#{'__struct__':='Elixir.EVM.SubState', 'logs':=[#{'__struct__':='Elixir.EVM.LogEntry', 'address':=<<_:160>>, 'data':=binary(), 'topics':=[binary()]}], 'refund':=integer(), 'suicide_list':=[<<_:160>>]}}, which is the expected return type for the callback of the 'Elixir.EVM.Interface.AccountInterface' behaviour

lib/evm/machine_code.ex:113: The variable _@1 can never match since previous clauses completely covered the type bitstring()
lib/evm/machine_code.ex:113: Cons will produce an improper list since its 2nd argument is binary(
10 changes: 5 additions & 5 deletions lib/evm.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ defmodule EVM do
# σ[a]
@type account :: %{
# σ[a]n
:nonce => integer(),
nonce: integer(),
# σ[a]b
:balance => integer(),
balance: integer(),
# σ[a]s
:storage => MerklePatriciaTree.Trie.t(),
storage: MerklePatriciaTree.Trie.t(),
# σ[a]c
:code => binary()
code: binary()
}
# σ
@type world_state :: %{
binary() => account()
address() => account()
}
@type trie_root :: MerklePatriciaTree.Trie.root_hash()
@type val :: integer()
Expand Down
23 changes: 21 additions & 2 deletions lib/evm/gas.ex
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ defmodule EVM.Gas do
@push_instrs Enum.map(0..32, fn n -> :"push#{n}" end)
@dup_instrs Enum.map(0..16, fn n -> :"dup#{n}" end)
@swap_instrs Enum.map(0..16, fn n -> :"swap#{n}" end)
@log_instrs Enum.map(1..4, fn n -> :"log#{n}" end)
@log_instrs Enum.map(0..4, fn n -> :"log#{n}" end)
@w_very_low_instr [
:add,
:sub,
Expand Down Expand Up @@ -390,6 +390,26 @@ defmodule EVM.Gas do
@g_call + call_value_cost(value) + gas_limit
end

def operation_cost(:log0, [_offset, size | _], _machine_state, _exec_end) do
@g_log + @g_logdata * size
end

def operation_cost(:log1, [_offset, size | _], _machine_state, _exec_end) do
@g_log + @g_logdata * size + @g_logtopic
end

def operation_cost(:log2, [_offset, size | _], _machine_state, _exec_end) do
@g_log + @g_logdata * size + @g_logtopic * 2
end

def operation_cost(:log3, [_offset, size | _], _machine_state, _exec_end) do
@g_log + @g_logdata * size + @g_logtopic * 3
end

def operation_cost(:log4, [_offset, size | _], _machine_state, _exec_end) do
@g_log + @g_logdata * size + @g_logtopic * 4
end

def operation_cost(operation, _inputs, _machine_state, _exec_env) do
cond do
operation in @w_very_low_instr -> @g_verylow
Expand All @@ -405,7 +425,6 @@ defmodule EVM.Gas do
operation == :balance -> @g_balance
operation == :sload -> @g_sload
operation == :jumpdest -> @g_jumpdest
operation in @log_instrs -> 0
true -> 0
end
end
Expand Down
100 changes: 100 additions & 0 deletions lib/evm/log_entry.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
defmodule EVM.LogEntry do
@moduledoc """
This module contains functions to work with logs.
"""

alias EVM.{Address, Helpers}

defstruct address: nil, topics: [], data: nil

@type t :: %__MODULE__{
address: EVM.address(),
topics: [binary()],
data: binary()
}

@doc """
Creates new log entry.
## Examples
iex> EVM.LogEntry.new(0, [0, 0, 0, 0], <<1>>)
%EVM.LogEntry{
address: <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>,
data: <<1>>,
topics: [0, 0, 0, 0]
}
iex> EVM.LogEntry.new( <<15, 87, 46, 82, 149, 197, 127, 21, 136, 111, 155, 38, 62, 47, 109, 45, 108, 123, 94, 198>>, [0, 0, 0, 0], <<1>>)
%EVM.LogEntry{
address: <<15, 87, 46, 82, 149, 197, 127, 21, 136, 111, 155, 38, 62, 47, 109,
45, 108, 123, 94, 198>>,
data: <<1>>,
topics: [0, 0, 0, 0]
}
"""
@spec new(integer() | binary(), [integer()], binary()) :: t()
def new(address, topics, data) do
address = if is_number(address), do: address |> Address.new(), else: address

%__MODULE__{
address: address,
topics: topics,
data: data
}
end

@doc """
Converts log struct to standard Ethereum list representation.
## Examples
iex> log = %EVM.LogEntry{
...> address: <<15, 87, 46, 82, 149, 197, 127, 21, 136, 111, 155, 38, 62, 47, 109,
...> 45, 108, 123, 94, 198>>,
...> data: <<255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
...> 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
...> 255, 255, 255>>,
...> topics: [0, 0, 0]
...> }
iex> log |> EVM.LogEntry.to_list
[
<<15, 87, 46, 82, 149, 197, 127, 21, 136, 111, 155, 38, 62, 47, 109, 45, 108,
123, 94, 198>>,
[
<<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0>>,
<<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0>>,
<<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0>>
],
<<255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255>>
]
"""
@spec to_list(t()) :: [binary()]
def to_list(log) do
topics =
log.topics
|> Enum.map(fn topic ->
topic |> Helpers.left_pad_bytes()
end)

[log.address, topics, log.data]
end
end

defimpl ExRLP.Encode, for: EVM.LogEntry do
alias ExRLP.Encode
alias EVM.LogEntry

@spec encode(LogEntry.t(), keyword()) :: binary()
def encode(log, options \\ []) do
log
|> LogEntry.to_list()
|> Encode.encode(options)
end
end
13 changes: 0 additions & 13 deletions lib/evm/operation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -220,10 +220,6 @@ defmodule EVM.Operation do
# nil
iex> EVM.Operation.run_operation(EVM.Operation.metadata(:stop), %EVM.MachineState{stack: [1, 2]}, %EVM.SubState{}, %EVM.ExecEnv{})
{%EVM.MachineState{stack: [1, 2]}, %EVM.SubState{}, %EVM.ExecEnv{}}
# Unimplemented
iex> EVM.Operation.run_operation(EVM.Operation.metadata(:log0), %EVM.MachineState{stack: [1, 2]}, %EVM.SubState{}, %EVM.ExecEnv{})
{%EVM.MachineState{stack: []}, %EVM.SubState{}, %EVM.ExecEnv{}}
"""
@spec run_operation(EVM.Operation.Metadata.t(), MachineState.t(), SubState.t(), ExecEnv.t()) ::
{MachineState.t(), SubState.t(), ExecEnv.t()}
Expand Down Expand Up @@ -316,9 +312,6 @@ defmodule EVM.Operation do
iex> EVM.Operation.merge_state(:noop, EVM.Operation.metadata(:add), %EVM.MachineState{}, %EVM.SubState{}, %EVM.ExecEnv{})
{%EVM.MachineState{}, %EVM.SubState{}, %EVM.ExecEnv{}}
iex> EVM.Operation.merge_state(:unimplemented, EVM.Operation.metadata(:blarg), %EVM.MachineState{}, %EVM.SubState{}, %EVM.ExecEnv{})
{%EVM.MachineState{}, %EVM.SubState{}, %EVM.ExecEnv{}}
iex> EVM.Operation.merge_state(%{stack: [1, 2, 3]}, :add, %EVM.MachineState{}, %EVM.SubState{}, %EVM.ExecEnv{})
{%EVM.MachineState{stack: [1, 2, 3]}, %EVM.SubState{}, %EVM.ExecEnv{}}
Expand Down Expand Up @@ -348,12 +341,6 @@ defmodule EVM.Operation do
{machine_state, sub_state, exec_env}
end

def merge_state(:unimplemented, operation, machine_state, sub_state, exec_env) do
Logger.debug("Executing (and ignoring) unimplemented operation: #{operation}")

{machine_state, sub_state, exec_env}
end

def merge_state(
updated_machine_state = %EVM.MachineState{},
_operation,
Expand Down
Loading

0 comments on commit 56890e6

Please sign in to comment.