Skip to content

Run London fork tests #2021

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

Merged
merged 10 commits into from
Sep 30, 2021
7 changes: 7 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ jobs:
- image: circleci/python:3.6
environment:
TOXENV: py36-native-blockchain-istanbul
py36-native-blockchain-london:
<<: *common
docker:
- image: circleci/python:3.6
environment:
TOXENV: py36-native-blockchain-london
py36-native-blockchain-petersburg:
<<: *common
docker:
Expand Down Expand Up @@ -247,6 +253,7 @@ workflows:
- py36-native-blockchain-frontier
- py36-native-blockchain-homestead
- py36-native-blockchain-istanbul
- py36-native-blockchain-london
- py36-native-blockchain-petersburg
- py36-native-blockchain-tangerine_whistle
- py36-native-blockchain-spurious_dragon
Expand Down
25 changes: 7 additions & 18 deletions docs/guides/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ This guide teaches how to use Py-EVM as a library. For contributors, please chec
:doc:`Contributing Guide </contributing>` which explains how to set everything up for development.


Installing on Ubuntu
--------------------
Installing Python on Ubuntu
---------------------------

Py-EVM requires Python 3.6 as well as some tools to compile its dependencies. On Ubuntu, the
``python3.6-dev`` package contains everything we need. Run the following command to install it.
Expand All @@ -25,30 +25,19 @@ we need to install the ``python3-pip`` package through the following command.
apt-get install python3-pip
.. note::
.. include:: /fragments/virtualenv_explainer.rst

Then, we need make to sure you have the latest version of ``pip`` so that all dependencies can be installed correctly:

.. code:: sh
pip3 install -U pip
Finally, we can install the ``py-evm`` package via pip.

.. code:: sh
pip3 install -U py-evm
Installing on macOS
-------------------
Installing Python on macOS
--------------------------

First, install Python 3 with brew:

.. code:: sh
brew install python3
Installing py-evm
-----------------

.. note::
.. include:: /fragments/virtualenv_explainer.rst

Expand Down
2 changes: 1 addition & 1 deletion docs/guides/understanding_the_mining_process.rst
Original file line number Diff line number Diff line change
Expand Up @@ -380,4 +380,4 @@ zero value transfer transaction.
... )

>>> chain.mine_block(mix_hash=mix_hash, nonce=nonce)
<ByzantiumBlock(#Block #1-0x41f6..2913)>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did this change? Something about the gas limit being off by one?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@carver yep

<ByzantiumBlock(#Block #1-0xe372..385c)>
15 changes: 10 additions & 5 deletions eth/_utils/headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,12 @@ def compute_gas_limit_bounds(previous_limit: int) -> Tuple[int, int]:
Compute the boundaries for the block gas limit based on the parent block.
"""
boundary_range = previous_limit // GAS_LIMIT_ADJUSTMENT_FACTOR
upper_bound = min(GAS_LIMIT_MAXIMUM, previous_limit + boundary_range)
lower_bound = max(GAS_LIMIT_MINIMUM, previous_limit - boundary_range)
return lower_bound, upper_bound

# the boundary range is the exclusive limit, therefore the inclusive bounds are
# (boundary_range - 1) and (boundary_range + 1) for upper and lower bounds, respectively
upper_bound_inclusive = min(GAS_LIMIT_MAXIMUM, previous_limit + boundary_range - 1)
lower_bound_inclusive = max(GAS_LIMIT_MINIMUM, previous_limit - boundary_range + 1)
return lower_bound_inclusive, upper_bound_inclusive


def compute_gas_limit(parent_header: BlockHeaderAPI, genesis_gas_limit: int) -> int:
Expand Down Expand Up @@ -152,12 +155,14 @@ def compute_gas_limit(parent_header: BlockHeaderAPI, genesis_gas_limit: int) ->

gas_limit = max(
GAS_LIMIT_MINIMUM,
parent_header.gas_limit - decay + usage_increase
# + 1 because the decay is an exclusive limit we have to remain inside of
(parent_header.gas_limit - decay + 1) + usage_increase
)

if gas_limit < GAS_LIMIT_MINIMUM:
return GAS_LIMIT_MINIMUM
elif gas_limit < genesis_gas_limit:
return parent_header.gas_limit + decay
# - 1 because the decay is an exclusive limit we have to remain inside of
return parent_header.gas_limit + decay - 1
else:
return gas_limit
4 changes: 2 additions & 2 deletions eth/_utils/rlp.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,6 @@ def validate_rlp_equal(obj_a: BaseBlock,


validate_imported_block_unchanged = validate_rlp_equal(
obj_a_name="block",
obj_b_name="imported block",
obj_a_name="locally executed block",
obj_b_name="proposed block",
)
2 changes: 2 additions & 0 deletions eth/tools/_utils/normalization.py
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,8 @@ def normalize_block(block: Dict[str, Any]) -> Dict[str, Any]:
for transaction
in block['transactions']
]
if 'expectException' in block:
normalized_block['expectException'] = block['expectException']
return normalized_block


Expand Down
7 changes: 7 additions & 0 deletions eth/vm/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,13 @@ def validate_uncle(cls,
f"the limit ({uncle.gas_limit})"
)

uncle_parent_gas_limit = uncle_parent.gas_limit
if not hasattr(uncle_parent, 'base_fee_per_gas') and hasattr(uncle, 'base_fee_per_gas'):
# if Berlin -> London transition, double the parent limit for validation
uncle_parent_gas_limit *= 2

validate_gas_limit(uncle.gas_limit, uncle_parent_gas_limit)
Comment on lines +672 to +677
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oof, this is a bummer, but I don't have a better suggestion right now.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hah, yes, same... I think it can use a refactor at some point for sure.


#
# State
#
Expand Down
14 changes: 10 additions & 4 deletions eth/vm/logic/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,15 @@ def __call__(self, computation: ComputationAPI) -> None:
computation.stack_push_int(0)
computation.return_data = b''
if insufficient_funds:
err_msg = f"Insufficient Funds: {storage_address_balance} < {stack_data.endowment}"
self.logger.debug2(
"%s failure: %s",
self.mnemonic,
f"Insufficient Funds: {storage_address_balance} < {stack_data.endowment}"
)
elif stack_too_deep:
err_msg = "Stack limit reached"
self.logger.debug2("%s failure: %s", self.mnemonic, err_msg,)
self.logger.debug2("%s failure: %s", self.mnemonic, "Stack limit reached")
Comment on lines +166 to +172
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was an implicit invariant check in the previous code that's not here anymore (because if neither of the if checks were true, the logger would fail on a missing err_msg. Maybe add an else: raise RuntimeError("unreachable")?

else:
raise RuntimeError("Invariant: error must be insufficient funds or stack too deep")
return

call_data = computation.memory_read_bytes(
Expand All @@ -183,11 +188,12 @@ def __call__(self, computation: ComputationAPI) -> None:
is_collision = computation.state.has_code_or_nonce(contract_address)

if is_collision:
computation.stack_push_int(0)
computation.return_data = b''
self.logger.debug2(
"Address collision while creating contract: %s",
encode_hex(contract_address),
)
computation.stack_push_int(0)
return

child_msg = computation.prepare_child_message(
Expand Down
1 change: 1 addition & 0 deletions newsfragments/2017.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Pass all London tests from the ethereum/tests repo
2 changes: 2 additions & 0 deletions newsfragments/2021.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Make header gas limit more restrictive. Was too permissive by one gas. Tightened the bounds.
- Validate uncle gas limits are within bounds. This was previously not validated at all.
1 change: 1 addition & 0 deletions newsfragments/2021.doc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Squash sphinx warnings with a small documentation reorg.
4 changes: 2 additions & 2 deletions tests/core/vm/test_london.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ def test_state_revert_on_reserved_0xEF_byte_for_create_transaction_post_london(

block_import, _, computations = chain.mine_all(
[create_successful_contract_transaction],
gas_limit=84082,
gas_limit=84081,
)
successful_create_computation = computations[0]
successful_create_computation_state = successful_create_computation.state
Expand Down Expand Up @@ -336,7 +336,7 @@ def test_state_does_not_revert_on_reserved_0xEF_byte_for_create_transaction_pre_

block_import, _, computations = chain.mine_all(
[create_contract_txn_0xef_byte],
gas_limit=99903
gas_limit=99904
)

computation = computations[0]
Expand Down
12 changes: 6 additions & 6 deletions tests/core/vm/test_vm.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def test_validate_gas_limit_almost_too_low(noproof_consensus_chain):
block1 = noproof_consensus_chain.mine_block()
block2 = noproof_consensus_chain.mine_block()

max_reduction = block1.header.gas_limit // constants.GAS_LIMIT_ADJUSTMENT_FACTOR
max_reduction = block1.header.gas_limit // constants.GAS_LIMIT_ADJUSTMENT_FACTOR - 1
barely_valid_low_gas_limit = block1.header.gas_limit - max_reduction
barely_valid_header = block2.header.copy(gas_limit=barely_valid_low_gas_limit)

Expand All @@ -146,8 +146,8 @@ def test_validate_gas_limit_too_low(noproof_consensus_chain):
block1 = noproof_consensus_chain.mine_block()
block2 = noproof_consensus_chain.mine_block()

max_reduction = block1.header.gas_limit // constants.GAS_LIMIT_ADJUSTMENT_FACTOR
invalid_low_gas_limit = block1.header.gas_limit - max_reduction - 1
exclusive_decrease_limit = block1.header.gas_limit // constants.GAS_LIMIT_ADJUSTMENT_FACTOR
invalid_low_gas_limit = block1.header.gas_limit - exclusive_decrease_limit
invalid_header = block2.header.copy(gas_limit=invalid_low_gas_limit)

vm = noproof_consensus_chain.get_vm(block2.header)
Expand All @@ -160,7 +160,7 @@ def test_validate_gas_limit_almost_too_high(noproof_consensus_chain):
block1 = noproof_consensus_chain.mine_block()
block2 = noproof_consensus_chain.mine_block()

max_increase = block1.header.gas_limit // constants.GAS_LIMIT_ADJUSTMENT_FACTOR
max_increase = block1.header.gas_limit // constants.GAS_LIMIT_ADJUSTMENT_FACTOR - 1
barely_valid_high_gas_limit = block1.header.gas_limit + max_increase
barely_valid_header = block2.header.copy(gas_limit=barely_valid_high_gas_limit)

Expand All @@ -173,8 +173,8 @@ def test_validate_gas_limit_too_high(noproof_consensus_chain):
block1 = noproof_consensus_chain.mine_block()
block2 = noproof_consensus_chain.mine_block()

max_increase = block1.header.gas_limit // constants.GAS_LIMIT_ADJUSTMENT_FACTOR
invalid_high_gas_limit = block1.header.gas_limit + max_increase + 1
exclusive_increase_limit = block1.header.gas_limit // constants.GAS_LIMIT_ADJUSTMENT_FACTOR
invalid_high_gas_limit = block1.header.gas_limit + exclusive_increase_limit
invalid_header = block2.header.copy(gas_limit=invalid_high_gas_limit)

vm = noproof_consensus_chain.get_vm(block2.header)
Expand Down
Loading