-
Notifications
You must be signed in to change notification settings - Fork 685
Byzantium Fork Rules #123
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
Byzantium Fork Rules #123
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
|
||
from evm.exceptions import ( | ||
OutOfGas, | ||
WriteProtection, | ||
) | ||
from evm.opcode import ( | ||
Opcode, | ||
|
@@ -42,6 +43,7 @@ def __call__(self, computation): | |
memory_output_start_position, | ||
memory_output_size, | ||
should_transfer_value, | ||
is_static, | ||
) = self.get_call_params(computation) | ||
|
||
computation.extend_memory(memory_input_start_position, memory_input_size) | ||
|
@@ -62,6 +64,7 @@ def __call__(self, computation): | |
stack_too_deep = computation.msg.depth + 1 > constants.STACK_DEPTH_LIMIT | ||
|
||
if insufficient_funds or stack_too_deep: | ||
computation.return_data = b'' | ||
if insufficient_funds: | ||
err_message = "Insufficient Funds: have: {0} | need: {1}".format( | ||
sender_balance, | ||
|
@@ -94,6 +97,7 @@ def __call__(self, computation): | |
'code': code, | ||
'code_address': code_address, | ||
'should_transfer_value': should_transfer_value, | ||
'is_static': is_static, | ||
} | ||
if sender is not None: | ||
child_msg_kwargs['sender'] = sender | ||
|
@@ -105,14 +109,18 @@ def __call__(self, computation): | |
if child_computation.error: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wouldn't it be better to explicitly check for None here instead? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think so or I'm not understanding your suggestion. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I meant There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 I'm going to file this away in a "Good First Issue" ticket. |
||
computation.stack.push(0) | ||
else: | ||
computation.stack.push(1) | ||
|
||
if not child_computation.error or not child_computation.error.zeros_return_data: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if it'd make sense to abstract this into a method on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 but going to do this as part of a "good first issue" ticket |
||
actual_output_size = min(memory_output_size, len(child_computation.output)) | ||
computation.gas_meter.return_gas(child_computation.gas_meter.gas_remaining) | ||
computation.memory.write( | ||
memory_output_start_position, | ||
actual_output_size, | ||
child_computation.output[:actual_output_size], | ||
) | ||
computation.stack.push(1) | ||
|
||
if not child_computation.error or not child_computation.error.burns_gas: | ||
computation.gas_meter.return_gas(child_computation.gas_meter.gas_remaining) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These two statements could maybe go into a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 but I'm going to add this as a "good first issue" (previously easy-pickings) ticket. |
||
|
||
|
||
class Call(BaseCall): | ||
|
@@ -146,6 +154,7 @@ def get_call_params(self, computation): | |
memory_output_start_position, | ||
memory_output_size, | ||
True, # should_transfer_value, | ||
computation.msg.is_static, | ||
) | ||
|
||
|
||
|
@@ -179,6 +188,7 @@ def get_call_params(self, computation): | |
memory_output_start_position, | ||
memory_output_size, | ||
True, # should_transfer_value, | ||
computation.msg.is_static, | ||
) | ||
|
||
|
||
|
@@ -215,6 +225,7 @@ def get_call_params(self, computation): | |
memory_output_start_position, | ||
memory_output_size, | ||
False, # should_transfer_value, | ||
computation.msg.is_static, | ||
) | ||
|
||
|
||
|
@@ -279,3 +290,42 @@ def compute_msg_extra_gas(self, computation, gas, to, value): | |
transfer_gas_fee = constants.GAS_CALLVALUE if value else 0 | ||
create_gas_fee = constants.GAS_NEWACCOUNT if (account_is_dead and value) else 0 | ||
return transfer_gas_fee + create_gas_fee | ||
|
||
|
||
# | ||
# Byzantium | ||
# | ||
class StaticCall(CallEIP161): | ||
def get_call_params(self, computation): | ||
gas = computation.stack.pop(type_hint=constants.UINT256) | ||
to = force_bytes_to_address(computation.stack.pop(type_hint=constants.BYTES)) | ||
|
||
( | ||
memory_input_start_position, | ||
memory_input_size, | ||
memory_output_start_position, | ||
memory_output_size, | ||
) = computation.stack.pop(num_items=4, type_hint=constants.UINT256) | ||
|
||
return ( | ||
gas, | ||
0, # value | ||
to, | ||
None, # sender | ||
None, # code_address | ||
memory_input_start_position, | ||
memory_input_size, | ||
memory_output_start_position, | ||
memory_output_size, | ||
False, # should_transfer_value, | ||
True, # is_static | ||
) | ||
|
||
|
||
class CallByzantium(CallEIP161): | ||
def get_call_params(self, computation): | ||
call_params = super(CallByzantium, self).get_call_params(computation) | ||
value = call_params[1] | ||
if computation.msg.is_static and value != 0: | ||
raise WriteProtection("Cannot modify state while inside of a STATICCALL context") | ||
return call_params |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,8 @@ | |
from evm import mnemonics | ||
from evm.exceptions import ( | ||
Halt, | ||
Revert, | ||
WriteProtection, | ||
) | ||
|
||
from evm.opcode import ( | ||
|
@@ -28,6 +30,16 @@ def return_op(computation): | |
raise Halt('RETURN') | ||
|
||
|
||
def revert(computation): | ||
start_position, size = computation.stack.pop(num_items=2, type_hint=constants.UINT256) | ||
|
||
computation.extend_memory(start_position, size) | ||
|
||
output = computation.memory.read(start_position, size) | ||
computation.output = bytes(output) | ||
raise Revert(computation.output) | ||
|
||
|
||
def selfdestruct(computation): | ||
beneficiary = force_bytes_to_address(computation.stack.pop(type_hint=constants.BYTES)) | ||
_selfdestruct(computation, beneficiary) | ||
|
@@ -147,10 +159,17 @@ def __call__(self, computation): | |
if child_computation.error: | ||
computation.stack.push(0) | ||
else: | ||
computation.gas_meter.return_gas(child_computation.gas_meter.gas_remaining) | ||
computation.stack.push(contract_address) | ||
computation.gas_meter.return_gas(child_computation.gas_meter.gas_remaining) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why was this change necessary? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The previous code with this nested into the |
||
|
||
|
||
class CreateEIP150(Create): | ||
def max_child_gas_modifier(self, gas): | ||
return max_child_gas_eip150(gas) | ||
|
||
|
||
class CreateByzantium(CreateEIP150): | ||
def __call__(self, computation): | ||
if computation.msg.is_static: | ||
raise WriteProtection("Cannot modify state while inside of a STATICCALL context") | ||
return super(CreateEIP150, self).__call__(computation) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BYZANTIUM_ROPSTEN_BLOCK is not used anywhere. Should it be in
RopstenChain
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I'm thinking it makes sense to migration the various fork-and-chain-specific block numbers into the fork or chain modules themselves.