Skip to content

Commit

Permalink
WIP: implement Create2 opcode
Browse files Browse the repository at this point in the history
Closes #1106
  • Loading branch information
cburgdorf committed Aug 15, 2018
1 parent a07dba0 commit 1861136
Showing 1 changed file with 73 additions and 14 deletions.
87 changes: 73 additions & 14 deletions eth/vm/logic/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
Address,
)

from eth_hash.auto import (
keccak
)

from eth import constants
from eth.exceptions import (
Halt,
Expand All @@ -13,6 +17,9 @@
force_bytes_to_address,
generate_contract_address,
)
from eth.utils.numeric import (
int_to_big_endian,
)
from eth.utils.hexadecimal import (
encode_hex,
)
Expand Down Expand Up @@ -99,45 +106,71 @@ def _selfdestruct(computation: BaseComputation, beneficiary: Address) -> None:
computation.register_account_for_deletion(beneficiary)
raise Halt('SELFDESTRUCT')

class CreateStackFrame:

def __init__(self,
endowment: int,
memory_start: int,
memory_length: int,
salt: int = None) -> None:

self.endowment = endowment
self.memory_start = memory_start
self.memory_length = memory_length
self.salt = salt

class Create(Opcode):

def max_child_gas_modifier(self, gas: int) -> int:
return gas

def __call__(self, computation: BaseComputation) -> None:
computation.consume_gas(self.gas_cost, reason=self.mnemonic)
def generate_contract_address(self,
stack_frame: CreateStackFrame,
call_data: bytes,
computation: BaseComputation) -> Address:

creation_nonce = computation.state.account_db.get_nonce(computation.msg.storage_address)
computation.state.account_db.increment_nonce(computation.msg.storage_address)

value, start_position, size = computation.stack_pop(
contract_address = generate_contract_address(
computation.msg.storage_address,
creation_nonce,
)

return contract_address

def get_stack_frame(self, computation: BaseComputation) -> CreateStackFrame:
endowment, memory_start, memory_length = computation.stack_pop(
num_items=3,
type_hint=constants.UINT256,
)

computation.extend_memory(start_position, size)
return CreateStackFrame(endowment, memory_start, memory_length)

def __call__(self, computation: BaseComputation) -> None:
computation.consume_gas(self.gas_cost, reason=self.mnemonic)

stack_frame = self.get_stack_frame(computation)

computation.extend_memory(stack_frame.memory_start, stack_frame.memory_length)

insufficient_funds = computation.state.account_db.get_balance(
computation.msg.storage_address
) < value
) < stack_frame.endowment
stack_too_deep = computation.msg.depth + 1 > constants.STACK_DEPTH_LIMIT

if insufficient_funds or stack_too_deep:
computation.stack_push(0)
return

call_data = computation.memory_read(start_position, size)
call_data = computation.memory_read(stack_frame.memory_start, stack_frame.memory_length)

create_msg_gas = self.max_child_gas_modifier(
computation.get_gas_remaining()
)
computation.consume_gas(create_msg_gas, reason="CREATE")

creation_nonce = computation.state.account_db.get_nonce(computation.msg.storage_address)
computation.state.account_db.increment_nonce(computation.msg.storage_address)

contract_address = generate_contract_address(
computation.msg.storage_address,
creation_nonce,
)
contract_address = self.generate_contract_address(stack_frame, call_data, computation)

is_collision = computation.state.account_db.account_has_code_or_nonce(contract_address)

Expand All @@ -152,7 +185,7 @@ def __call__(self, computation: BaseComputation) -> None:
child_msg = computation.prepare_child_message(
gas=create_msg_gas,
to=constants.CREATE_CONTRACT_ADDRESS,
value=value,
value=stack_frame.endowment,
data=b'',
code=call_data,
create_address=contract_address,
Expand All @@ -177,3 +210,29 @@ def __call__(self, computation: BaseComputation) -> None:
if computation.msg.is_static:
raise WriteProtection("Cannot modify state while inside of a STATICCALL context")
return super().__call__(computation)


class Create2(CreateByzantium):

def get_stack_frame(self, computation: BaseComputation) -> CreateStackFrame:

endowment, memory_start, memory_length, salt = computation.stack_pop(
num_items=4,
type_hint=constants.UINT256,
)

return CreateStackFrame(endowment, memory_start, memory_length, salt)

def generate_contract_address(self,
stack_frame: CreateStackFrame,
call_data: bytes,
computation: BaseComputation) -> Address:

return Address(
keccak(
encode_hex('0xff')
+ computation.msg.storage_address
+ int_to_big_endian(stack_frame.salt)
+ keccak(call_data)
)[-20:]
)

0 comments on commit 1861136

Please sign in to comment.