Skip to content

Commit 7d619a4

Browse files
committed
eip-3541: reserve '0xEF' byte in contract code + related tests
1 parent d37b308 commit 7d619a4

File tree

11 files changed

+389
-80
lines changed

11 files changed

+389
-80
lines changed

eth/exceptions.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,11 @@ class OutOfBoundsRead(VMError):
195195
boundaries of the buffer (such as with RETURNDATACOPY)
196196
"""
197197
pass
198+
199+
200+
class ReservedBytesInCode(VMError):
201+
"""
202+
Raised when bytes for the code to be deployed are reserved
203+
for a particular reason.
204+
"""
205+
pass

eth/vm/forks/frontier/constants.py

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,2 @@
1-
from eth_typing import (
2-
Address
3-
)
4-
5-
CREATE_CONTRACT_ADDRESS = Address(b'')
6-
7-
8-
#
9-
# Difficulty
10-
#
111
FRONTIER_DIFFICULTY_ADJUSTMENT_CUTOFF = 13
12-
13-
14-
#
15-
# Stack Limit
16-
#
17-
STACK_DEPTH_LIMIT = 1024
18-
19-
20-
#
21-
# Gas Costs and Refunds
22-
#
232
REFUND_SELFDESTRUCT = 24000
24-
GAS_CODEDEPOSIT = 200

eth/vm/forks/homestead/constants.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,3 @@
22
# Difficulty
33
#
44
HOMESTEAD_DIFFICULTY_ADJUSTMENT_CUTOFF = 10
5-
6-
7-
#
8-
# Gas Costs and Refunds
9-
#
10-
GAS_CODEDEPOSIT = 200

eth/vm/forks/london/computation.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
1+
from eth_utils import encode_hex, keccak
2+
3+
from eth import constants
4+
from eth.abc import ComputationAPI, MessageAPI, StateAPI, TransactionContextAPI
5+
from eth.exceptions import OutOfGas, ReservedBytesInCode
16
from eth.vm.forks.berlin.computation import (
27
BerlinComputation,
38
)
49

510
from .opcodes import LONDON_OPCODES
11+
from ..london.constants import EIP3541_RESERVED_STARTING_BYTE
12+
from ..spurious_dragon.constants import EIP170_CODE_SIZE_LIMIT
613

714

815
class LondonComputation(BerlinComputation):
@@ -11,3 +18,62 @@ class LondonComputation(BerlinComputation):
1118
Inherits from :class:`~eth.vm.forks.berlin.BerlinComputation`
1219
"""
1320
opcodes = LONDON_OPCODES
21+
22+
@classmethod
23+
def apply_create_message(
24+
cls,
25+
state: StateAPI,
26+
message: MessageAPI,
27+
transaction_context: TransactionContextAPI
28+
) -> ComputationAPI:
29+
30+
snapshot = state.snapshot()
31+
32+
# EIP161 nonce incrementation
33+
state.increment_nonce(message.storage_address)
34+
35+
computation = cls.apply_message(state, message, transaction_context)
36+
37+
if computation.is_error:
38+
state.revert(snapshot)
39+
return computation
40+
else:
41+
contract_code = computation.output
42+
43+
if contract_code and len(contract_code) >= EIP170_CODE_SIZE_LIMIT:
44+
computation.error = OutOfGas(
45+
f"Contract code size exceeds EIP170 limit of {EIP170_CODE_SIZE_LIMIT}."
46+
f" Got code of size: {len(contract_code)}"
47+
)
48+
state.revert(snapshot)
49+
elif contract_code:
50+
contract_code_gas_cost = len(contract_code) * constants.GAS_CODEDEPOSIT
51+
try:
52+
computation.consume_gas(
53+
contract_code_gas_cost,
54+
reason="Write contract code for CREATE / CREATE2",
55+
)
56+
except OutOfGas as err:
57+
computation.error = err
58+
state.revert(snapshot)
59+
else:
60+
if contract_code[:1] == EIP3541_RESERVED_STARTING_BYTE:
61+
# As per EIP-3541, gas is still consumed on a revert of this nature
62+
state.revert(snapshot)
63+
raise ReservedBytesInCode(
64+
"Contract code begins with EIP3541 reserved byte '0xEF'."
65+
)
66+
else:
67+
if cls.logger:
68+
cls.logger.debug2(
69+
"SETTING CODE: %s -> length: %s | hash: %s",
70+
encode_hex(message.storage_address),
71+
len(contract_code),
72+
encode_hex(keccak(contract_code))
73+
)
74+
75+
state.set_code(message.storage_address, contract_code)
76+
state.commit(snapshot)
77+
else:
78+
state.commit(snapshot)
79+
return computation

eth/vm/forks/london/constants.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@
1111
BASE_FEE_MAX_CHANGE_DENOMINATOR = 8
1212
INITIAL_BASE_FEE = 1000000000
1313
ELASTICITY_MULTIPLIER = 2
14+
15+
EIP3541_RESERVED_STARTING_BYTE = b'\xef'

eth/vm/forks/spurious_dragon/constants.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
#
2-
# Gas Costs and Refunds
3-
#
4-
GAS_CODEDEPOSIT = 200
5-
6-
71
# https://github.com/ethereum/EIPs/issues/160
82
GAS_EXP_EIP160 = 10
93
GAS_EXPBYTE_EIP160 = 50

newsfragments/2018.feature.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Implement `EIP-3554 <https://eips.ethereum.org/EIPS/eip-3554>`_ for London support.
2+
3+
Implement `EIP-3541 <https://eips.ethereum.org/EIPS/eip-3541>`_ for London support.

tests/core/vm/conftest.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import pytest
2+
from eth_utils import to_canonical_address
3+
4+
from eth.vm.transaction_context import BaseTransactionContext
5+
6+
7+
NORMALIZED_ADDRESS_A = "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6"
8+
NORMALIZED_ADDRESS_B = "0xcd1722f3947def4cf144679da39c4c32bdc35681"
9+
CANONICAL_ADDRESS_A = to_canonical_address("0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6")
10+
CANONICAL_ADDRESS_B = to_canonical_address("0xcd1722f3947def4cf144679da39c4c32bdc35681")
11+
12+
13+
@pytest.fixture
14+
def transaction_context():
15+
tx_context = BaseTransactionContext(
16+
gas_price=1,
17+
origin=CANONICAL_ADDRESS_B,
18+
)
19+
return tx_context
20+

tests/core/vm/test_base_computation.py

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import pytest
22

33
from eth_utils import (
4-
to_canonical_address,
54
ValidationError,
65
)
76

@@ -18,12 +17,7 @@
1817
from eth.vm.transaction_context import (
1918
BaseTransactionContext,
2019
)
21-
22-
23-
NORMALIZED_ADDRESS_A = "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6"
24-
NORMALIZED_ADDRESS_B = "0xcd1722f3947def4cf144679da39c4c32bdc35681"
25-
CANONICAL_ADDRESS_A = to_canonical_address("0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6")
26-
CANONICAL_ADDRESS_B = to_canonical_address("0xcd1722f3947def4cf144679da39c4c32bdc35681")
20+
from tests.core.vm.conftest import CANONICAL_ADDRESS_A, CANONICAL_ADDRESS_B, NORMALIZED_ADDRESS_A
2721

2822

2923
class DummyComputation(BaseComputation):
@@ -41,15 +35,6 @@ def get_intrinsic_gas(self):
4135
return 0
4236

4337

44-
@pytest.fixture
45-
def transaction_context():
46-
tx_context = DummyTransactionContext(
47-
gas_price=1,
48-
origin=CANONICAL_ADDRESS_B,
49-
)
50-
return tx_context
51-
52-
5338
@pytest.fixture
5439
def message():
5540
message = Message(

tests/core/vm/test_frontier_computation.py

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,12 @@
11
import pytest
22

3-
from eth_utils import (
4-
to_canonical_address,
5-
)
6-
73
from eth.vm.message import (
84
Message,
95
)
106
from eth.vm.forks.frontier.computation import (
117
FrontierComputation,
128
)
13-
from eth.vm.transaction_context import (
14-
BaseTransactionContext,
15-
)
16-
17-
18-
NORMALIZED_ADDRESS_A = "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6"
19-
NORMALIZED_ADDRESS_B = "0xcd1722f3947def4cf144679da39c4c32bdc35681"
20-
CANONICAL_ADDRESS_A = to_canonical_address("0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6")
21-
CANONICAL_ADDRESS_B = to_canonical_address("0xcd1722f3947def4cf144679da39c4c32bdc35681")
9+
from tests.core.vm.conftest import CANONICAL_ADDRESS_A, CANONICAL_ADDRESS_B
2210

2311

2412
@pytest.fixture
@@ -28,15 +16,6 @@ def state(chain_without_block_validation):
2816
return state
2917

3018

31-
@pytest.fixture
32-
def transaction_context():
33-
tx_context = BaseTransactionContext(
34-
gas_price=1,
35-
origin=CANONICAL_ADDRESS_B,
36-
)
37-
return tx_context
38-
39-
4019
@pytest.fixture
4120
def message():
4221
message = Message(

0 commit comments

Comments
 (0)