Skip to content

Commit

Permalink
implement extcodehash (#420)
Browse files Browse the repository at this point in the history
* implement extcodehash

* update dialyzer ignore file
  • Loading branch information
ayrat555 authored Sep 12, 2018
1 parent e41a8f0 commit 5e8f1be
Show file tree
Hide file tree
Showing 15 changed files with 85 additions and 17 deletions.
30 changes: 15 additions & 15 deletions .dialyzer.ignore-warnings
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,21 @@

# evm warnings

apps/evm/lib/evm/functions.ex:181: Function 'not_enough_gas?'/2 has no local return
apps/evm/lib/evm/functions.ex:193: Function 'is_invalid_jump_destination?'/3 will never be called
apps/evm/lib/evm/functions.ex:203: Function 'static_state_modification?'/2 will never be called
apps/evm/lib/evm/gas.ex:137: Function cost/2 has no local return
apps/evm/lib/evm/gas.ex:137: Function cost/3 has no local return
apps/evm/lib/evm/gas.ex:142: The call 'Elixir.EVM.Gas':operation_cost(atom(),_inputs@1::[integer()],_machine_state@1::#{'__struct__':='Elixir.EVM.MachineState', 'active_words':=integer(), 'gas':=integer(), 'last_return_data':=binary(), 'memory':=binary(), 'previously_active_words':=integer(), 'program_counter':=integer(), 'stack':=[integer()]},_exec_env@1::#{'__struct__':='Elixir.EVM.ExecEnv', 'account_interface':=atom(), 'address':=<<_:160>>, 'block_interface':=atom(), 'config':=atom(), 'data':=binary(), 'gas_price':=integer(), 'machine_code':=binary(), 'originator':=<<_:160>>, 'sender':=<<_:160>>, 'stack_depth':=integer(), 'static':=boolean(), 'value_in_wei':=integer()}) breaks the contract (atom(),['Elixir.EVM':val()],['Elixir.EVM':val()],'Elixir.EVM.MachineState':t()) -> t() | 'nil'
apps/evm/lib/evm/gas.ex:303: Function operation_cost/0 has no local return
apps/evm/lib/evm/gas.ex:303: The call 'Elixir.EVM.Gas':operation_cost('nil','nil','nil','nil') breaks the contract (atom(),['Elixir.EVM':val()],['Elixir.EVM':val()],'Elixir.EVM.MachineState':t()) -> t() | 'nil'
apps/evm/lib/evm/gas.ex:303: Function operation_cost/1 has no local return
apps/evm/lib/evm/gas.ex:303: The call 'Elixir.EVM.Gas':operation_cost(__@1::any(),'nil','nil','nil') breaks the contract (atom(),['Elixir.EVM':val()],['Elixir.EVM':val()],'Elixir.EVM.MachineState':t()) -> t() | 'nil'
apps/evm/lib/evm/gas.ex:303: Function operation_cost/2 has no local return
apps/evm/lib/evm/gas.ex:303: The call 'Elixir.EVM.Gas':operation_cost(__@1::any(),__@2::any(),'nil','nil') breaks the contract (atom(),['Elixir.EVM':val()],['Elixir.EVM':val()],'Elixir.EVM.MachineState':t()) -> t() | 'nil'
apps/evm/lib/evm/gas.ex:303: Function operation_cost/3 has no local return
apps/evm/lib/evm/gas.ex:303: The call 'Elixir.EVM.Gas':operation_cost(__@1::any(),__@2::any(),__@3::any(),'nil') breaks the contract (atom(),['Elixir.EVM':val()],['Elixir.EVM':val()],'Elixir.EVM.MachineState':t()) -> t() | 'nil'
apps/evm/lib/evm/gas.ex:562: Function gas_cost_for_nested_operation/2 will never be called
apps/evm/lib/evm/functions.ex:184: Function 'not_enough_gas?'/2 has no local return
apps/evm/lib/evm/functions.ex:196: Function 'is_invalid_jump_destination?'/3 will never be called
apps/evm/lib/evm/functions.ex:206: Function 'static_state_modification?'/2 will never be called
apps/evm/lib/evm/gas.ex:138: Function cost/2 has no local return
apps/evm/lib/evm/gas.ex:138: Function cost/3 has no local return
apps/evm/lib/evm/gas.ex:143: The call 'Elixir.EVM.Gas':operation_cost(atom(),_inputs@1::[integer()],_machine_state@1::#{'__struct__':='Elixir.EVM.MachineState', 'active_words':=integer(), 'gas':=integer(), 'last_return_data':=binary(), 'memory':=binary(), 'previously_active_words':=integer(), 'program_counter':=integer(), 'stack':=[integer()]},_exec_env@1::#{'__struct__':='Elixir.EVM.ExecEnv', 'account_interface':=atom(), 'address':=<<_:160>>, 'block_interface':=atom(), 'config':=atom(), 'data':=binary(), 'gas_price':=integer(), 'machine_code':=binary(), 'originator':=<<_:160>>, 'sender':=<<_:160>>, 'stack_depth':=integer(), 'static':=boolean(), 'value_in_wei':=integer()}) breaks the contract (atom(),['Elixir.EVM':val()],['Elixir.EVM':val()],'Elixir.EVM.MachineState':t()) -> t() | 'nil'
apps/evm/lib/evm/gas.ex:304: Function operation_cost/0 has no local return
apps/evm/lib/evm/gas.ex:304: The call 'Elixir.EVM.Gas':operation_cost('nil','nil','nil','nil') breaks the contract (atom(),['Elixir.EVM':val()],['Elixir.EVM':val()],'Elixir.EVM.MachineState':t()) -> t() | 'nil'
apps/evm/lib/evm/gas.ex:304: Function operation_cost/1 has no local return
apps/evm/lib/evm/gas.ex:304: The call 'Elixir.EVM.Gas':operation_cost(__@1::any(),'nil','nil','nil') breaks the contract (atom(),['Elixir.EVM':val()],['Elixir.EVM':val()],'Elixir.EVM.MachineState':t()) -> t() | 'nil'
apps/evm/lib/evm/gas.ex:304: Function operation_cost/2 has no local return
apps/evm/lib/evm/gas.ex:304: The call 'Elixir.EVM.Gas':operation_cost(__@1::any(),__@2::any(),'nil','nil') breaks the contract (atom(),['Elixir.EVM':val()],['Elixir.EVM':val()],'Elixir.EVM.MachineState':t()) -> t() | 'nil'
apps/evm/lib/evm/gas.ex:304: Function operation_cost/3 has no local return
apps/evm/lib/evm/gas.ex:304: The call 'Elixir.EVM.Gas':operation_cost(__@1::any(),__@2::any(),__@3::any(),'nil') breaks the contract (atom(),['Elixir.EVM':val()],['Elixir.EVM':val()],'Elixir.EVM.MachineState':t()) -> t() | 'nil'
apps/evm/lib/evm/gas.ex:566: Function gas_cost_for_nested_operation/2 will never be called
apps/evm/lib/evm/machine_state.ex:53: Function subtract_gas/2 has no local return
apps/evm/lib/evm/operation/environmental_information.ex:114: Function calldataload/2 has no local return
apps/evm/lib/evm/operation/environmental_information.ex:117: The call 'Elixir.EVM.Helpers':decode_signed(binary()) breaks the contract (integer() | 'nil') -> 'Elixir.EVM':val() | 'nil'
Expand Down
7 changes: 7 additions & 0 deletions apps/blockchain/lib/blockchain/interface/account_interface.ex
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ defimpl EVM.Interface.AccountInterface, for: Blockchain.Interface.AccountInterfa
end
end

@spec get_account_code_hash(AccountInterface.t(), EVM.address()) :: binary() | nil
def get_account_code_hash(account_interface, address) do
account = Account.get_account(account_interface.state, address)

unless is_nil(account), do: account.code_hash
end

@doc """
Given an account interface and an address, increments the nonce on the account,
returning both a new `AccountInterface` and the previous nonce value.
Expand Down
4 changes: 4 additions & 0 deletions apps/evm/lib/evm/configuration.ex
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,8 @@ defprotocol EVM.Configuration do
# EIP145
@spec has_shift_operations?(t) :: boolean()
def has_shift_operations?(t)

# EIP1052
@spec has_extcodehash?(t) :: boolean()
def has_extcodehash?(t)
end
3 changes: 3 additions & 0 deletions apps/evm/lib/evm/configuration/byzantium.ex
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,7 @@ defimpl EVM.Configuration, for: EVM.Configuration.Byzantium do
@spec has_shift_operations?(Configuration.t()) :: boolean()
def has_shift_operations?(config),
do: Configuration.has_shift_operations?(config.fallback_config)

@spec has_extcodehash?(Configuration.t()) :: boolean()
def has_extcodehash?(config), do: Configuration.has_extcodehash?(config.fallback_config)
end
6 changes: 5 additions & 1 deletion apps/evm/lib/evm/configuration/constantinople.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
defmodule EVM.Configuration.Constantinople do
defstruct fallback_config: EVM.Configuration.Byzantium.new(),
has_shift_operations: true
has_shift_operations: true,
has_extcodehash: true

def new do
%__MODULE__{}
Expand Down Expand Up @@ -92,4 +93,7 @@ defimpl EVM.Configuration, for: EVM.Configuration.Constantinople do
@spec has_shift_operations?(Configuration.t()) :: boolean()
def has_shift_operations?(config),
do: config.has_shift_operations

@spec has_extcodehash?(Configuration.t()) :: boolean()
def has_extcodehash?(config), do: config.has_extcodehash
end
3 changes: 3 additions & 0 deletions apps/evm/lib/evm/configuration/eip150.ex
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,7 @@ defimpl EVM.Configuration, for: EVM.Configuration.EIP150 do
@spec has_shift_operations?(Configuration.t()) :: boolean()
def has_shift_operations?(config),
do: Configuration.has_shift_operations?(config.fallback_config)

@spec has_extcodehash?(Configuration.t()) :: boolean()
def has_extcodehash?(config), do: Configuration.has_extcodehash?(config.fallback_config)
end
3 changes: 3 additions & 0 deletions apps/evm/lib/evm/configuration/eip158.ex
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,7 @@ defimpl EVM.Configuration, for: EVM.Configuration.EIP158 do
@spec has_shift_operations?(Configuration.t()) :: boolean()
def has_shift_operations?(config),
do: Configuration.has_shift_operations?(config.fallback_config)

@spec has_extcodehash?(Configuration.t()) :: boolean()
def has_extcodehash?(config), do: Configuration.has_extcodehash?(config.fallback_config)
end
6 changes: 5 additions & 1 deletion apps/evm/lib/evm/configuration/frontier.ex
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ defmodule EVM.Configuration.Frontier do
has_ec_add_builtin: false,
has_ec_mult_builtin: false,
has_ec_pairing_builtin: false,
has_shift_operations: false
has_shift_operations: false,
has_extcodehash: false

def new do
%__MODULE__{}
Expand Down Expand Up @@ -104,4 +105,7 @@ defimpl EVM.Configuration, for: EVM.Configuration.Frontier do

@spec has_shift_operations?(Configuration.t()) :: boolean()
def has_shift_operations?(config), do: config.has_shift_operations

@spec has_extcodehash?(Configuration.t()) :: boolean()
def has_extcodehash?(config), do: config.has_extcodehash
end
3 changes: 3 additions & 0 deletions apps/evm/lib/evm/configuration/homestead.ex
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,7 @@ defimpl EVM.Configuration, for: EVM.Configuration.Homestead do
@spec has_shift_operations?(Configuration.t()) :: boolean()
def has_shift_operations?(config),
do: Configuration.has_shift_operations?(config.fallback_config)

@spec has_extcodehash?(Configuration.t()) :: boolean()
def has_extcodehash?(config), do: Configuration.has_extcodehash?(config.fallback_config)
end
3 changes: 3 additions & 0 deletions apps/evm/lib/evm/functions.ex
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,9 @@ defmodule EVM.Functions do
:sar ->
if Configuration.has_shift_operations?(config), do: operation_metadata

:extcodehash ->
if Configuration.has_extcodehash?(config), do: operation_metadata

_ ->
operation_metadata
end
Expand Down
4 changes: 4 additions & 0 deletions apps/evm/lib/evm/gas.ex
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ defmodule EVM.Gas do
@g_copy 3
# Payment for BLOCKHASH operation
@g_blockhash 20
@g_extcodehash 400

@w_zero_instr [:stop, :return, :revert]
@w_base_instr [
Expand Down Expand Up @@ -485,6 +486,9 @@ defmodule EVM.Gas do
operation == :jumpdest ->
@g_jumpdest

operation == :extcodehash ->
@g_extcodehash

true ->
0
end
Expand Down
3 changes: 3 additions & 0 deletions apps/evm/lib/evm/interface/account_interface.ex
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ defprotocol EVM.Interface.AccountInterface do
@spec get_account_nonce(EVM.Interface.AccountInterface.t(), EVM.address()) :: integer()
def get_account_nonce(mock_account_interface, address)

@spec get_account_code_hash(t, EVM.address()) :: binary() | nil
def get_account_code_hash(t, address)

@spec increment_account_nonce(t, EVM.address()) :: {t(), integer()}
def increment_account_nonce(t, address)

Expand Down
7 changes: 7 additions & 0 deletions apps/evm/lib/evm/interface/mock/mock_account_interface.ex
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ defimpl EVM.Interface.AccountInterface, for: EVM.Interface.Mock.MockAccountInter
end
end

@spec get_account_code_hash(EVM.Interface.AccountInterface.t(), EVM.address()) :: binary() | nil
def get_account_code_hash(mock_account_interface, address) do
account = get_account(mock_account_interface, address)

unless is_nil(account), do: account.code_hash
end

defp get_account(mock_account_interface, address) do
Map.get(mock_account_interface.account_map, address)
end
Expand Down
12 changes: 12 additions & 0 deletions apps/evm/lib/evm/operation/environmental_information.ex
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,18 @@ defmodule EVM.Operation.EnvironmentalInformation do
end
end

@spec extcodehash(Operation.stack_args(), Operation.vm_map()) :: Operation.op_result()
def extcodehash([address], %{exec_env: exec_env}) do
wrapped_address = Helpers.wrap_address(address)
hash = AccountInterface.get_account_code_hash(exec_env.account_interface, wrapped_address)

if is_nil(hash) do
0
else
hash
end
end

@doc """
Get size of output data from the previous call from the current environment.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,14 @@ defmodule EVM.Operation.Metadata.EnvironmentalInformation do
input_count: 3,
output_count: 0,
group: :environmental_information
},
%{
id: 0x3F,
description: "Returns the keccak256 hash of a contract’s code",
sym: :extcodehash,
input_count: 1,
output_count: 1,
group: :environmental_information
}
],
do: struct(EVM.Operation.Metadata, operation)
Expand Down

0 comments on commit 5e8f1be

Please sign in to comment.