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

Fix EVM tests #127

Merged
merged 1 commit into from
Jun 4, 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
17 changes: 8 additions & 9 deletions apps/blockchain/lib/blockchain/account.ex
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ defmodule Blockchain.Account do

@doc """
Completely removes an account from the world state.
This is used, for instance, after a suicide.
This is used, for instance, after a selfdestruct.
This is defined from Eq.(71) and Eq.(80) in the Yellow Paper.

## Examples
Expand Down Expand Up @@ -354,14 +354,13 @@ defmodule Blockchain.Account do
@doc """
Helper function for transferring eth for one account to another.
This handles the fact that a new account may be shadow-created if
it receives eth. See Section 8, Eq.(100), Eq.(101), Eq.(102), Eq.(103),
and Eq.(104) of the Yellow Paper.

The Yellow Paper assumes this function will always succeed (as the checks
occur before this function is called), but we'll check just in case
this function is not properly called. The only case will be if the
sending account is nil or has an insufficient balance, but we add
a few extra checks just in case.
it receives eth. See Section 8, Eq.(100-104) of the Yellow Paper.

The Yellow Paper assumes this function will always succeed
(as the checks occur before this function is called),
but we'll check just in case this function is not properly called.
The only case will be if the sending account is nil or has an insufficient balance,
but we add a few extra checks just in case.

Note: transferring value to an empty account still adds value to said account,
even though it's effectively a zombie.
Expand Down
12 changes: 6 additions & 6 deletions apps/blockchain/lib/blockchain/interface/account_interface.ex
Original file line number Diff line number Diff line change
Expand Up @@ -214,30 +214,30 @@ defimpl EVM.Interface.AccountInterface, for: Blockchain.Interface.AccountInterfa
end

@doc """
Suicides an account (err.. SELFDESTRUCT is the new word). This removes any trace
of the account from the system.
Destructs an account (SELFDESTRUCT operation in YP).
This removes any trace of the account from the system.

## Examples

iex> MerklePatriciaTree.Test.random_ets_db()
...> |> MerklePatriciaTree.Trie.new()
...> |> Blockchain.Account.add_wei(<<1::160>>, 5)
...> |> Blockchain.Interface.AccountInterface.new()
...> |> EVM.Interface.AccountInterface.suicide_account(<<1::160>>)
...> |> EVM.Interface.AccountInterface.destroy_account(<<1::160>>)
...> |> EVM.Interface.AccountInterface.get_account_balance(<<1::160>>)
nil

iex> MerklePatriciaTree.Test.random_ets_db()
...> |> MerklePatriciaTree.Trie.new()
...> |> Blockchain.Account.add_wei(<<1::160>>, 5)
...> |> Blockchain.Interface.AccountInterface.new()
...> |> EVM.Interface.AccountInterface.suicide_account(<<2::160>>)
...> |> EVM.Interface.AccountInterface.destroy_account(<<2::160>>)
...> |> EVM.Interface.AccountInterface.get_account_balance(<<1::160>>)
5
"""
@spec suicide_account(EVM.Interface.AccountInterface.t(), EVM.address()) ::
@spec destroy_account(EVM.Interface.AccountInterface.t(), EVM.address()) ::
EVM.Interface.AccountInterface.t()
def suicide_account(account_interface, address) do
def destroy_account(account_interface, address) do
updated_state = Account.del_account(account_interface.state, address)

%{account_interface | state: updated_state}
Expand Down
6 changes: 3 additions & 3 deletions apps/blockchain/lib/blockchain/transaction.ex
Original file line number Diff line number Diff line change
Expand Up @@ -361,15 +361,15 @@ defmodule Blockchain.Transaction do

state_after_gas = finalize_transaction_gas(state_p, sender, tx, refund, block_header)

state_after_suicides =
Enum.reduce(sub_state.suicide_list, state_after_gas, fn address, state ->
state_after_selfdestruct =
Enum.reduce(sub_state.selfdestruct_list, state_after_gas, fn address, state ->
Account.del_account(state, address)
end)

expended_gas = tx.gas_limit - remaining_gas

# { σ', Υ^g, Υ^l }, as defined in Eq.(79) and Eq.(80)
{state_after_suicides, expended_gas, sub_state.logs}
{state_after_selfdestruct, expended_gas, sub_state.logs}
end

@doc """
Expand Down
2 changes: 1 addition & 1 deletion apps/evm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ As discussed in the paper, we define a few data structures.

* State - The world state of Ethereum, defined as the root hash of a Merkle Patricia Trie containing all account data. See Section 4.1 of the Yellow Paper, or explore the [merkle_patricia_tree](https://github.com/exthereum/merkle_patricia_tree) umbrella project in this repo.
* The Machine State - This structure effectively encodes the current context of a running VM (e.g. the program counter, the current memory data, etc). This structure is simply used during execution of the program, and thrown away after it completes. Before we finish, we extract the gas used and return value from this object.
* The Sub State - The sub state tracks the suicide list (contracts to destroy), the logs and the refund (for cleaning up storage) for a contract execution.
* The Sub State - The sub state tracks the selfdestruct list (contracts to destroy), the logs and the refund (for cleaning up storage) for a contract execution.
* The Execution Environment - This tracks information about the call into a contract, such as the machine code itself and the value passed to the contract or message call. Other than stack depth, this is generally not mutated during execution of the machine.

# Examples
Expand Down
3 changes: 3 additions & 0 deletions apps/evm/lib/evm/address.ex
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,11 @@ defmodule EVM.Address do
address
|> :binary.encode_unsigned()
|> EVM.Helpers.left_pad_bytes(@size)
|> EVM.Helpers.take_n_last_bytes(@size)
end

def new(address), do: address

@doc """
Returns an address given an address and a nonce.
"""
Expand Down
8 changes: 6 additions & 2 deletions apps/evm/lib/evm/debugger/breakpoint.ex
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,12 @@ defmodule EVM.Debugger.Breakpoint do
"""
@spec matches?(t, EVM.MachineState.t(), EVM.SubState.t(), EVM.ExecEnv.t()) :: boolean()
def matches?(breakpoint, machine_state, _sub_state, exec_env) do
breakpoint.enabled and break_on_next_pc?(breakpoint, machine_state.program_counter) and
should_break = break_on_next_pc?(breakpoint, machine_state.program_counter)

breakpoint.enabled and should_break and
Enum.all?(breakpoint.conditions, fn {condition, condition_val} ->
case condition do
:sender -> exec_env.sender == condition_val
:address -> exec_env.address == condition_val
end
end)
Expand Down Expand Up @@ -159,6 +162,7 @@ defmodule EVM.Debugger.Breakpoint do
conditions =
for {k, v} <- breakpoint.conditions do
case k do
:sender -> "sender address 0x#{Base.encode16(v, case: :lower)}"
:address -> "contract address 0x#{Base.encode16(v, case: :lower)}"
end
end
Expand Down Expand Up @@ -295,7 +299,7 @@ defmodule EVM.Debugger.Breakpoint do
end
end

# Returns true if we should break on the next instruction
# Returns true if we should break on the next instruction.

# This is will be true if we're instructed to break on :next or :start, or
# when the machine's breakpoint's pc matches the machine's pc.
Expand Down
7 changes: 3 additions & 4 deletions apps/evm/lib/evm/exec_env.ex
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,9 @@ defmodule EVM.ExecEnv do
AccountInterface.get_storage(account_interface, address, key)
end

@spec suicide_account(t()) :: t()
def suicide_account(exec_env = %{account_interface: account_interface, address: address}) do
account_interface = AccountInterface.suicide_account(account_interface, address)

@spec destroy_account(t()) :: t()
def destroy_account(exec_env = %{account_interface: account_interface, address: address}) do
account_interface = AccountInterface.destroy_account(account_interface, address)
Map.put(exec_env, :account_interface, account_interface)
end

Expand Down
4 changes: 2 additions & 2 deletions apps/evm/lib/evm/functions.ex
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ defmodule EVM.Functions do
iex> EVM.Functions.is_normal_halting?(%EVM.MachineState{program_counter: 0}, %EVM.ExecEnv{machine_code: <<EVM.Operation.encode(:stop)>>})
<<>>

iex> EVM.Functions.is_normal_halting?(%EVM.MachineState{program_counter: 0}, %EVM.ExecEnv{machine_code: <<EVM.Operation.encode(:suicide)>>})
iex> EVM.Functions.is_normal_halting?(%EVM.MachineState{program_counter: 0}, %EVM.ExecEnv{machine_code: <<EVM.Operation.encode(:selfdestruct)>>})
<<>>

iex> EVM.Functions.is_normal_halting?(%EVM.MachineState{stack: [0, 1], memory: <<0xabcd::16>>}, %EVM.ExecEnv{machine_code: <<EVM.Operation.encode(:return)>>})
Expand All @@ -41,7 +41,7 @@ defmodule EVM.Functions do
def is_normal_halting?(machine_state, exec_env) do
case MachineCode.current_operation(machine_state, exec_env).sym do
:return -> h_return(machine_state)
x when x == :stop or x == :suicide -> <<>>
x when x == :stop or x == :selfdestruct -> <<>>
_ -> nil
end
end
Expand Down
12 changes: 6 additions & 6 deletions apps/evm/lib/evm/gas.ex
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ defmodule EVM.Gas do
@g_sreset 5000
# Refund given (added into refund counter) when the storage value is set to zero from non-zero.
@g_sclear 15000
# Refund given (added into refund counter) for suiciding an account.
@g_suicide 24000
# Amount of gas to pay for a SUICIDE operation.
@g_suicide 5000
# Refund given (added into refund counter) for selfdestructing an account.
@r_selfdestruct 24000
# Amount of gas to pay for a SELFDESTRUCT operation.
@g_selfdestruct 5000
# Paid for a CREATE operation.
@g_create 32000
# Paid per byte for a CREATE operation to succeed in placing code into state.
Expand All @@ -48,7 +48,7 @@ defmodule EVM.Gas do
@g_callvalue 9000
# A stipend for the called contract subtracted from Gcallvalue for a non-zero value transfer.
@g_callstipend 2300
# Paid for a CALL or SUICIDE operation which creates an account.
# Paid for a CALL or SELFDESTRUCT operation which creates an account.
@g_newaccount 25000
# Partial payment for an EXP operation.
@g_exp 10
Expand Down Expand Up @@ -81,7 +81,7 @@ defmodule EVM.Gas do
# Payment for BLOCKHASH operation
@g_blockhash 20

@w_zero_instr [:stop, :return, :suicide]
@w_zero_instr [:stop, :return, :selfdestruct]
@w_base_instr [
:address,
:origin,
Expand Down
4 changes: 2 additions & 2 deletions apps/evm/lib/evm/interface/account_interface.ex
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ defprotocol EVM.Interface.AccountInterface do
@spec put_storage(t, EVM.address(), integer(), integer()) :: t
def put_storage(t, address, key, value)

@spec suicide_account(t, EVM.address()) :: t
def suicide_account(t, address)
@spec destroy_account(t, EVM.address()) :: t
def destroy_account(t, address)

@spec dump_storage(t) :: %{EVM.address() => EVM.val()}
def dump_storage(t)
Expand Down
30 changes: 13 additions & 17 deletions apps/evm/lib/evm/interface/mock/mock_account_interface.ex
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,7 @@ defimpl EVM.Interface.AccountInterface, for: EVM.Interface.Mock.MockAccountInter
if account do
update_storage(account, key, value)
else
new_account(%{
storage: %{key => value}
})
new_account(%{storage: %{key => value}})
end

put_account(mock_account_interface, address, account)
Expand All @@ -116,26 +114,24 @@ defimpl EVM.Interface.AccountInterface, for: EVM.Interface.Mock.MockAccountInter
end

defp put_account(mock_account_interface, address, account) do
%{
mock_account_interface
| account_map: Map.put(mock_account_interface.account_map, address, account)
}
account_map = Map.put(mock_account_interface.account_map, address, account)
%{mock_account_interface | account_map: account_map}
end

defp new_account(opts \\ %{}) do
Map.merge(
%{
storage: %{},
nonce: 0,
balance: 0
},
opts
)
account = %{
storage: %{},
nonce: 0,
code: <<>>,
balance: 0
}

Map.merge(account, opts)
end

@spec suicide_account(EVM.Interface.AccountInterface.t(), EVM.address()) ::
@spec destroy_account(EVM.Interface.AccountInterface.t(), EVM.address()) ::
EVM.Interface.AccountInterface.t()
def suicide_account(mock_account_interface, address) do
def destroy_account(mock_account_interface, address) do
account_map =
mock_account_interface.account_map
|> Map.delete(address)
Expand Down
2 changes: 1 addition & 1 deletion apps/evm/lib/evm/machine_code.ex
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ defmodule EVM.MachineCode do
[:push1, 3, :push1, 5, :add, :return]

iex> EVM.MachineCode.decompile(<<97, 0, 4, 128, 97, 0, 14, 96, 0, 57, 97, 0, 18, 86, 96, 0, 53, 255, 91, 96, 0, 243>>)
[:push2, 0, 4, :dup1, :push2, 0, 14, :push1, 0, :codecopy, :push2, 0, 18, :jump, :push1, 0, :calldataload, :suicide, :jumpdest, :push1, 0, :return]
[:push2, 0, 4, :dup1, :push2, 0, 14, :push1, 0, :codecopy, :push2, 0, 18, :jump, :push1, 0, :calldataload, :selfdestruct, :jumpdest, :push1, 0, :return]

iex> EVM.MachineCode.decompile(<<>>)
[]
Expand Down
2 changes: 1 addition & 1 deletion apps/evm/lib/evm/machine_state.ex
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ defmodule EVM.MachineState do
end

@doc """
Pops n values off the stack
Pops n values off the stack.

## Examples

Expand Down
6 changes: 1 addition & 5 deletions apps/evm/lib/evm/operation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@ defmodule EVM.Operation do
"""

alias MathHelper
alias EVM.Helpers
alias EVM.ExecEnv
alias EVM.MachineState
alias EVM.Stack
alias EVM.SubState
alias EVM.{Helpers, ExecEnv, MachineState, Stack, SubState}
alias EVM.Operation.Metadata.StopAndArithmetic, as: StopAndArithmeticMetadata
alias EVM.Operation.Metadata.ComparisonAndBitwiseLogic, as: ComparisonAndBitwiseLogicMetadata
alias EVM.Operation.Metadata.SHA3, as: SHA3Metadata
Expand Down
20 changes: 10 additions & 10 deletions apps/evm/lib/evm/operation/logging.ex
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ defmodule EVM.Operation.Logging do
...> program_counter: 40,
...> stack: []
...> }
iex> sub_state = %EVM.SubState{logs: [], refund: 0, suicide_list: []}
iex> sub_state = %EVM.SubState{logs: [], refund: 0, selfdestruct_list: []}
iex> vm_map = %{sub_state: sub_state, exec_env: env, machine_state: machine_state}
iex> EVM.Operation.Logging.log0([0, 32], vm_map)
%{
Expand All @@ -37,7 +37,7 @@ defmodule EVM.Operation.Logging do
}
],
refund: 0,
suicide_list: []
selfdestruct_list: []
}
}
"""
Expand Down Expand Up @@ -66,7 +66,7 @@ defmodule EVM.Operation.Logging do
...> program_counter: 40,
...> stack: []
...> }
iex> sub_state = %EVM.SubState{logs: [], refund: 0, suicide_list: []}
iex> sub_state = %EVM.SubState{logs: [], refund: 0, selfdestruct_list: []}
iex> vm_map = %{sub_state: sub_state, exec_env: env, machine_state: machine_state}
iex> args = [0, 32, 115792089237316195423570985008687907853269984665640564039457584007913129639935]
iex> EVM.Operation.Logging.log1(args, vm_map)
Expand All @@ -83,7 +83,7 @@ defmodule EVM.Operation.Logging do
}
],
refund: 0,
suicide_list: []
selfdestruct_list: []
}
}
"""
Expand Down Expand Up @@ -112,7 +112,7 @@ defmodule EVM.Operation.Logging do
...> program_counter: 40,
...> stack: []
...> }
iex> sub_state = %EVM.SubState{logs: [], refund: 0, suicide_list: []}
iex> sub_state = %EVM.SubState{logs: [], refund: 0, selfdestruct_list: []}
iex> vm_map = %{sub_state: sub_state, exec_env: env, machine_state: machine_state}
iex> args = [0, 32,
...> 115792089237316195423570985008687907853269984665640564039457584007913129639935,
Expand All @@ -132,7 +132,7 @@ defmodule EVM.Operation.Logging do
}
],
refund: 0,
suicide_list: []
selfdestruct_list: []
}
}
"""
Expand Down Expand Up @@ -161,7 +161,7 @@ defmodule EVM.Operation.Logging do
...> program_counter: 40,
...> stack: []
...> }
iex> sub_state = %EVM.SubState{logs: [], refund: 0, suicide_list: []}
iex> sub_state = %EVM.SubState{logs: [], refund: 0, selfdestruct_list: []}
iex> vm_map = %{sub_state: sub_state, exec_env: env, machine_state: machine_state}
iex> args = [1, 0, 0, 0, 0]
iex> EVM.Operation.Logging.log3(args, vm_map)
Expand All @@ -176,7 +176,7 @@ defmodule EVM.Operation.Logging do
}
],
refund: 0,
suicide_list: []
selfdestruct_list: []
}
}
"""
Expand Down Expand Up @@ -208,7 +208,7 @@ defmodule EVM.Operation.Logging do
...> program_counter: 40,
...> stack: []
...> }
iex> sub_state = %EVM.SubState{logs: [], refund: 0, suicide_list: []}
iex> sub_state = %EVM.SubState{logs: [], refund: 0, selfdestruct_list: []}
iex> vm_map = %{sub_state: sub_state, exec_env: env, machine_state: machine_state}
iex> args = [115792089237316195423570985008687907853269984665640564039457584007913129639935,
...> 1, 0, 0, 0, 0]
Expand All @@ -224,7 +224,7 @@ defmodule EVM.Operation.Logging do
}
],
refund: 0,
suicide_list: []
selfdestruct_list: []
}
}
"""
Expand Down
2 changes: 1 addition & 1 deletion apps/evm/lib/evm/operation/metadata/system.ex
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ defmodule EVM.Operation.Metadata.System do
%{
id: 0xFF,
description: "Halt execution and register account for later deletion.",
sym: :suicide,
sym: :selfdestruct,
input_count: 1,
output_count: 0,
group: :system
Expand Down
Loading