Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement extcodehash #420

Merged
merged 2 commits into from
Sep 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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