Skip to content

Commit d8523ed

Browse files
feat(pre_alloc): Add maximum bytecode size limit for contract deployment (#2150)
* feat(pre_alloc): Add maximum bytecode size limit for contract deployment * refactor(benchmark): resolve contract size limit failing cases * feat(pre_alloc): integrate fork dependency for dynamic bytecode size limit * refactor: remove hardcoded value
1 parent 68489a2 commit d8523ed

File tree

3 files changed

+27
-4
lines changed

3 files changed

+27
-4
lines changed

src/pytest_plugins/filler/pre_alloc.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,15 @@ class Alloc(BaseAlloc):
9696
_contract_address_iterator: Iterator[Address] = PrivateAttr()
9797
_eoa_iterator: Iterator[EOA] = PrivateAttr()
9898
_evm_code_type: EVMCodeType | None = PrivateAttr(None)
99+
_fork: Fork = PrivateAttr()
99100

100101
def __init__(
101102
self,
102103
*args,
103104
alloc_mode: AllocMode,
104105
contract_address_iterator: Iterator[Address],
105106
eoa_iterator: Iterator[EOA],
107+
fork: Fork,
106108
evm_code_type: EVMCodeType | None = None,
107109
**kwargs,
108110
):
@@ -112,6 +114,7 @@ def __init__(
112114
self._contract_address_iterator = contract_address_iterator
113115
self._eoa_iterator = eoa_iterator
114116
self._evm_code_type = evm_code_type
117+
self._fork = fork
115118

116119
def __setitem__(self, address: Address | FixedSizeBytesConvertible, account: Account | None):
117120
"""Set account associated with an address."""
@@ -163,12 +166,19 @@ def deploy_contract(
163166
if self._alloc_mode == AllocMode.STRICT:
164167
assert Number(nonce) >= 1, "impossible to deploy contract with nonce lower than one"
165168

169+
code = self.code_pre_processor(code, evm_code_type=evm_code_type)
170+
code_bytes = bytes(code) if not isinstance(code, (bytes, str)) else code
171+
max_code_size = self._fork.max_code_size()
172+
assert len(code_bytes) <= max_code_size, (
173+
f"code too large: {len(code_bytes)} > {max_code_size}"
174+
)
175+
166176
super().__setitem__(
167177
contract_address,
168178
Account(
169179
nonce=nonce,
170180
balance=balance,
171-
code=self.code_pre_processor(code, evm_code_type=evm_code_type),
181+
code=code,
172182
storage=storage,
173183
),
174184
)
@@ -424,11 +434,13 @@ def pre(
424434
contract_address_iterator: Iterator[Address],
425435
eoa_iterator: Iterator[EOA],
426436
evm_code_type: EVMCodeType,
437+
fork: Fork,
427438
) -> Alloc:
428439
"""Return default pre allocation for all tests (Empty alloc)."""
429440
return Alloc(
430441
alloc_mode=alloc_mode,
431442
contract_address_iterator=contract_address_iterator,
432443
eoa_iterator=eoa_iterator,
444+
fork=fork,
433445
evm_code_type=evm_code_type,
434446
)

src/pytest_plugins/filler/tests/test_pre_alloc.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import pytest
66

77
from ethereum_test_base_types import Address, TestPrivateKey, TestPrivateKey2
8+
from ethereum_test_forks import Fork, Prague
89
from ethereum_test_types import EOA
910
from ethereum_test_vm import EVMCodeType
1011
from ethereum_test_vm import Opcodes as Op
@@ -18,7 +19,9 @@
1819

1920

2021
def create_test_alloc(
21-
alloc_mode: AllocMode = AllocMode.PERMISSIVE, evm_code_type: EVMCodeType = EVMCodeType.LEGACY
22+
alloc_mode: AllocMode = AllocMode.PERMISSIVE,
23+
fork: Fork = Prague,
24+
evm_code_type: EVMCodeType = EVMCodeType.LEGACY,
2225
) -> Alloc:
2326
"""Create a test Alloc instance with default iterators."""
2427
contract_iter = iter(
@@ -33,6 +36,7 @@ def create_test_alloc(
3336
alloc_mode=alloc_mode,
3437
contract_address_iterator=contract_iter,
3538
eoa_iterator=eoa_iter,
39+
fork=fork,
3640
evm_code_type=evm_code_type,
3741
)
3842

tests/benchmark/test_worst_compute.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2978,13 +2978,20 @@ def test_worst_push(
29782978
):
29792979
"""Test running a block with as many PUSH as possible."""
29802980
op = opcode[1] if opcode.has_data_portion() else opcode
2981-
opcode_sequence = op * fork.max_stack_height()
2982-
target_contract_address = pre.deploy_contract(code=opcode_sequence)
2981+
2982+
op_seq = Bytecode()
2983+
for _ in range(fork.max_stack_height()):
2984+
if len(op_seq) + len(op) > fork.max_code_size():
2985+
break
2986+
op_seq += op
2987+
2988+
target_contract_address = pre.deploy_contract(code=op_seq)
29832989

29842990
calldata = Bytecode()
29852991
attack_block = Op.POP(Op.STATICCALL(Op.GAS, target_contract_address, 0, 0, 0, 0))
29862992

29872993
code = code_loop_precompile_call(calldata, attack_block, fork)
2994+
29882995
code_address = pre.deploy_contract(code=code)
29892996

29902997
tx = Transaction(

0 commit comments

Comments
 (0)