diff --git a/eth/vm/forks/london/computation.py b/eth/vm/forks/london/computation.py index 0e3dfcfa34..ae72e8d627 100644 --- a/eth/vm/forks/london/computation.py +++ b/eth/vm/forks/london/computation.py @@ -15,7 +15,9 @@ class LondonComputation(BerlinComputation): opcodes = LONDON_OPCODES @classmethod - def validate_new_contract_code(cls, contract_code: bytes) -> None: + def validate_contract_code(cls, contract_code: bytes) -> None: + super().validate_contract_code(contract_code) + if contract_code[:1] == EIP3541_RESERVED_STARTING_BYTE: raise ReservedBytesInCode( "Contract code begins with EIP3541 reserved byte '0xEF'." diff --git a/eth/vm/forks/spurious_dragon/computation.py b/eth/vm/forks/spurious_dragon/computation.py index 4713dc52b6..41104b3728 100644 --- a/eth/vm/forks/spurious_dragon/computation.py +++ b/eth/vm/forks/spurious_dragon/computation.py @@ -51,31 +51,22 @@ def apply_create_message( else: contract_code = computation.output - if contract_code and len(contract_code) >= EIP170_CODE_SIZE_LIMIT: - computation.error = OutOfGas( - f"Contract code size exceeds EIP170 limit of {EIP170_CODE_SIZE_LIMIT}." - f" Got code of size: {len(contract_code)}" - ) - state.revert(snapshot) - elif contract_code: - contract_code_gas_cost = len(contract_code) * constants.GAS_CODEDEPOSIT + if contract_code: try: + cls.validate_contract_code(contract_code) + + contract_code_gas_cost = len(contract_code) * constants.GAS_CODEDEPOSIT computation.consume_gas( contract_code_gas_cost, reason="Write contract code for CREATE", ) - except OutOfGas as err: + except VMError as err: # Different from Frontier: reverts state on gas failure while # writing contract code. computation.error = err state.revert(snapshot) + cls.logger.debug2(f"VMError setting contract code: {err}") else: - try: - cls.validate_new_contract_code(contract_code) - except VMError as err: - state.revert(snapshot) - raise err - if cls.logger: cls.logger.debug2( "SETTING CODE: %s -> length: %s | hash: %s", @@ -91,6 +82,9 @@ def apply_create_message( return computation @classmethod - def validate_new_contract_code(cls, contract_code: bytes) -> None: - # helps facilitate EIP-3541 validation in LondonComputation - pass + def validate_contract_code(cls, contract_code: bytes) -> None: + if len(contract_code) >= EIP170_CODE_SIZE_LIMIT: + raise OutOfGas( + f"Contract code size exceeds EIP170 limit of {EIP170_CODE_SIZE_LIMIT}." + f" Got code of size: {len(contract_code)}" + ) diff --git a/fixtures b/fixtures index 6f41f7b617..52cb3b3e72 160000 --- a/fixtures +++ b/fixtures @@ -1 +1 @@ -Subproject commit 6f41f7b6171f6da759060db177b440030dadd5b0 +Subproject commit 52cb3b3e724d13943bd8a457ed70929f98b9b8bf diff --git a/tests/core/vm/test_london.py b/tests/core/vm/test_london.py index 070cc3e3c6..1ab1dfdb69 100644 --- a/tests/core/vm/test_london.py +++ b/tests/core/vm/test_london.py @@ -9,7 +9,7 @@ from eth.chains.mainnet import ( MAINNET_VMS, ) -from eth.exceptions import InvalidInstruction, ReservedBytesInCode +from eth.exceptions import InvalidInstruction from eth.vm.forks import BerlinVM from eth.tools.factories.transaction import ( new_dynamic_fee_transaction, new_transaction, @@ -182,10 +182,7 @@ def test_revert_on_reserved_0xEF_byte_for_CREATE_and_CREATE2_post_london( ) assert revert_create_computation.is_error - assert isinstance(revert_create_computation.error, ReservedBytesInCode) - assert "0xef" in repr(revert_create_computation.error).lower() - - assert revert_create_computation.get_gas_used() == 40000 # assert gas is consumed + assert 35000 < revert_create_computation.get_gas_used() < 40000 # assert gas is still consumed assert revert_create_computation.get_gas_refund() == 0 @@ -259,24 +256,19 @@ def test_state_revert_on_reserved_0xEF_byte_for_create_transaction_post_london( data=data, ) - with pytest.raises(ReservedBytesInCode): - block_import, _, computations = chain.mine_all( - [create_contract_txn_reserved_byte], - gas_limit=84082 - ) + block_import, _, computations = chain.mine_all( + [create_contract_txn_reserved_byte], + gas_limit=84082 + ) - reverted_computation = computations[0] - mined_header = block_import.imported_block.header - end_balance = reverted_computation.state.get_balance(funded_address) + reverted_computation = computations[0] + mined_header = block_import.imported_block.header - assert reverted_computation.is_error - assert isinstance(reverted_computation.error, ReservedBytesInCode) - assert "0xef" in repr(reverted_computation.error).lower() + assert reverted_computation.is_error + assert "0xef" in repr(reverted_computation.error).lower() - assert reverted_computation.get_nonce(funded_address) == 1 # assert nonce is still 1 - # reverted txn consumes the gas: - assert mined_header.gas_used == 60000 - assert end_balance == new_balance - 60000 + # reverted txn consumes the gas: + assert mined_header.gas_used == 60000 @pytest.mark.parametrize(