-
Notifications
You must be signed in to change notification settings - Fork 654
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
Byzantium Fork Rules #123
Conversation
121b572
to
61701d7
Compare
3562916
to
6ffd4af
Compare
evm/chains/chain.py
Outdated
else: | ||
raise VMNotFound("No vm available for block #{0}".format(block_number)) | ||
|
||
vm_class = base_vm_class.configure(chaindb=self.chaindb) |
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.
TODO: undo this. No longer necessary.
maybe green? This is going to get split into about 5 pull requests with some minor refactors extracted into their own pull requests. |
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.
Just me annotating the pull request so that I have an indicator on whether I've pulled all the things out.
evm/chains/chain.py
Outdated
'IMPORTED_BLOCK: number %s | hash %s', | ||
imported_block.number, | ||
encode_hex(imported_block.hash), | ||
) |
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.
TODO: extract
evm/constants.py
Outdated
GAS_SUICIDE_NEWACCOUNT = 25000 | ||
GAS_SELFDESTRUCT = 0 | ||
GAS_SELFDESTRUCT_EIP150 = 5000 | ||
GAS_SELFDESTRUCT_NEWACCOUNT = 25000 |
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.
TODO: extract
evm/constants.py
Outdated
@@ -110,7 +116,8 @@ | |||
DIFFICULTY_MINIMUM = 131072 | |||
|
|||
FRONTIER_DIFFICULTY_ADJUSTMENT_CUTOFF = 13 | |||
HOMESTEAD_DIFF_ADJUSTMENT_CUTOFF = 10 | |||
HOMESTEAD_DIFFICULTY_ADJUSTMENT_CUTOFF = 10 |
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.
TODO: extract
evm/logic/block.py
Outdated
@@ -3,9 +3,7 @@ | |||
|
|||
def blockhash(computation): | |||
block_number = computation.stack.pop(type_hint=constants.UINT256) | |||
|
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.
TODO: undo
evm/logic/call.py
Outdated
else: | ||
code = state_db.get_code(to) | ||
|
||
child_msg_kwargs = { |
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.
TODO: move back into else
block
logic_fn=system.suicide_eip161, | ||
mnemonic=mnemonics.SUICIDE, | ||
gas_cost=constants.GAS_SUICIDE_EIP150, | ||
opcode_values.SELFDESTRUCT: as_opcode( |
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.
TODO: extract
tests/core/vm/test_computation.py
Outdated
@@ -167,7 +161,7 @@ def test_add_log_entry_raises_if_data_isnt_in_bytes(computation): | |||
def test_add_log_entry(computation): | |||
# Adds log entry to log entries | |||
computation.add_log_entry(CANONICAL_ADDRESS_A, [1, 2, 3], b'') | |||
assert computation.log_entries == [(b'\x0fW.R\x95\xc5\x7f\x15\x88o\x9b&>/m-l{^\xc6', | |||
assert computation.log_entries == [(b'\x0fW.R\x95\xc5\x7f\x15\x88o\x9b&>/m-l\x7b^\xc6', |
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.
TODO: extract
tests/core/vm/test_computation.py
Outdated
assert computation.get_log_entries() == () | ||
|
||
|
||
def test_get_gas_refund(computation, create_error): | ||
def test_get_gas_refund(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.
TODO: extract
) | ||
elif 'TransitionTests/bcHomesteadToEIP150' in fixture_path: | ||
elif network == 'Homestead': |
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.
TODO: extract
tests/json-fixtures/test_state.py
Outdated
@@ -185,8 +190,8 @@ def test_state_fixtures(fixture, fixture_vm_class): | |||
|
|||
try: | |||
computation = vm.apply_transaction(transaction) | |||
except ValidationError: | |||
transaction_error = True | |||
except ValidationError as err: |
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.
TODO: extract
b7b1bda
to
fc77ba5
Compare
fc77ba5
to
d58f6a7
Compare
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.
Looking good! I have a few questions/suggestions, but nothing major
# ByzantiumVM | ||
# | ||
BYZANTIUM_MAINNET_BLOCK = 4370000 | ||
BYZANTIUM_ROPSTEN_BLOCK = 1700000 |
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.
evm/exceptions.py
Outdated
|
||
class OutOfBoundsRead(VMError): | ||
""" | ||
Error raised to indicate an attempt was made to read data beyond then |
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.
s/then/the?
@@ -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 comment
The 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 comment
The 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 comment
The reason will be displayed to describe this comment to others. Learn more.
I meant if child_computation.error is not None:
, just in case at some point we have an error class that for some reason implements __bool__()
and returns False there, this would no longer work as expected. I can't think why we'd have an error class that would do that, but in general I prefer to explicitly check for None
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.
👍 I'm going to file this away in a "Good First Issue" ticket.
evm/logic/call.py
Outdated
@@ -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, # is_static |
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.
I'd drop this comment as it doesn't add anything
@@ -105,14 +109,18 @@ def __call__(self, computation): | |||
if child_computation.error: | |||
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 comment
The 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 Computation
, so that we don't need to reach so many levels down into the exception's attributes. Something like Computation.should_return_data()
?
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.
+1 but going to do this as part of a "good first issue" ticket
) | ||
|
||
|
||
ZERO = (bn128.FQ2.one(), bn128.FQ2.one(), bn128.FQ2.zero()) |
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.
I find this an odd name choice for a 3-tuple with seemingly non-zero items, but maybe I'm missing something?
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.
This code is a refactored version of vitalik's implementation in pyethereum. I'm not familiar enough with what is actually going on here to know what a better name would be :(
evm/vm/forks/byzantium/headers.py
Outdated
def compute_byzantium_difficulty(parent_header, timestamp): | ||
""" | ||
https://github.com/ethereum/EIPs/issues/100 | ||
TODO: figure out how to know about uncles in this context... |
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.
Is this still TODO? If so, it'd be nice if you could expand on what exactly you mean
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.
This was from before I'd put in the optimization to just check if parent_header.uncles_hash != EMPTY_UNCLE_HASH
and was thinking that I'd actually need to be able to fetch the uncles to know how many there were.
evm/vm/forks/byzantium/opcodes.py
Outdated
from evm.vm.forks.spurious_dragon.opcodes import SPURIOUS_DRAGON_OPCODES | ||
|
||
|
||
def no_static(opcode_fn): |
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.
The name here had me confused at first, but then I realized it's used to ensure a given opcode_fn is not passed a computation with a static msg, right? Maybe rename it to ensure_no_static()
?
evm/vm/forks/byzantium/opcodes.py
Outdated
@functools.wraps(opcode_fn) | ||
def inner(computation): | ||
if computation.msg.is_static: | ||
raise WriteProtection("Cannot modify state while inside of a STATICCALL context") |
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.
Also, the exception msg here is quite misleading, as it's saying we cannot modify the state when the msg is actually static? Or have I gotten this backwards?
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.
I think the txt is correct.
"Since we are inside of a STATICCALL context, the state cannot be modified
@@ -33,6 +33,7 @@ class Message(object): | |||
create_address = None | |||
|
|||
should_transfer_value = None | |||
is_static = None |
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.
Why does it default to None? To force all message types to define it?
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.
Same convention that I think has raised questions previously. This is merely a pattern I use to make it easy to know what properties an object has.
It you have strong feelings about this pattern I'm all ears because it's something that grew organically and I'm not sure it's a good pattern.
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.
Not really, I just find it odd for bool attributes to have a default of None, but I think it's more of a gut feeling than anything justifiable
What was wrong?
Need support for the Byzantium fork.
How was it fixed?
Cute Animal Picture