From c8b19110594b75e4d37d37ff10ee7c23d9a48e1d Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Mon, 15 Sep 2025 17:45:52 +0800 Subject: [PATCH 1/4] feat(pre_alloc): Add maximum bytecode size limit for contract deployment --- src/pytest_plugins/filler/pre_alloc.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/pytest_plugins/filler/pre_alloc.py b/src/pytest_plugins/filler/pre_alloc.py index 49a9a4594bc..60bc7c35f9c 100644 --- a/src/pytest_plugins/filler/pre_alloc.py +++ b/src/pytest_plugins/filler/pre_alloc.py @@ -36,6 +36,8 @@ CONTRACT_START_ADDRESS_DEFAULT = 0x1000000000000000000000000000000000001000 CONTRACT_ADDRESS_INCREMENTS_DEFAULT = 0x100 +MAX_BYTECODE_SIZE = 24576 + def pytest_addoption(parser: pytest.Parser): """Add command-line options to pytest.""" @@ -162,12 +164,18 @@ def deploy_contract( if self._alloc_mode == AllocMode.STRICT: assert Number(nonce) >= 1, "impossible to deploy contract with nonce lower than one" + code = self.code_pre_processor(code, evm_code_type=evm_code_type) + code_bytes = bytes(code) if not isinstance(code, (bytes, str)) else code + assert len(code_bytes) <= MAX_BYTECODE_SIZE, ( + f"code too large: {len(code_bytes)} > {MAX_BYTECODE_SIZE}" + ) + super().__setitem__( contract_address, Account( nonce=nonce, balance=balance, - code=self.code_pre_processor(code, evm_code_type=evm_code_type), + code=code, storage=storage, ), ) From c76fcd9b4b56e1bc7155267525f6ad133f4edf35 Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Mon, 15 Sep 2025 18:13:07 +0800 Subject: [PATCH 2/4] refactor(benchmark): resolve contract size limit failing cases --- tests/benchmark/test_worst_compute.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/benchmark/test_worst_compute.py b/tests/benchmark/test_worst_compute.py index 90ce819a7eb..e685a727ea6 100644 --- a/tests/benchmark/test_worst_compute.py +++ b/tests/benchmark/test_worst_compute.py @@ -2872,13 +2872,20 @@ def test_worst_push( ): """Test running a block with as many PUSH as possible.""" op = opcode[1] if opcode.has_data_portion() else opcode - opcode_sequence = op * fork.max_stack_height() - target_contract_address = pre.deploy_contract(code=opcode_sequence) + + op_seq = Bytecode() + for _ in range(fork.max_stack_height()): + if len(op_seq) + len(op) > fork.max_code_size(): + break + op_seq += op + + target_contract_address = pre.deploy_contract(code=op_seq) calldata = Bytecode() attack_block = Op.POP(Op.STATICCALL(Op.GAS, target_contract_address, 0, 0, 0, 0)) code = code_loop_precompile_call(calldata, attack_block, fork) + code_address = pre.deploy_contract(code=code) tx = Transaction( From f98308661914c6fae1319b30133f678a2fb34f09 Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Mon, 15 Sep 2025 18:24:32 +0800 Subject: [PATCH 3/4] feat(pre_alloc): integrate fork dependency for dynamic bytecode size limit --- src/pytest_plugins/filler/pre_alloc.py | 12 ++++++++---- src/pytest_plugins/filler/tests/test_pre_alloc.py | 2 ++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/pytest_plugins/filler/pre_alloc.py b/src/pytest_plugins/filler/pre_alloc.py index 60bc7c35f9c..0de14dc52c8 100644 --- a/src/pytest_plugins/filler/pre_alloc.py +++ b/src/pytest_plugins/filler/pre_alloc.py @@ -36,8 +36,6 @@ CONTRACT_START_ADDRESS_DEFAULT = 0x1000000000000000000000000000000000001000 CONTRACT_ADDRESS_INCREMENTS_DEFAULT = 0x100 -MAX_BYTECODE_SIZE = 24576 - def pytest_addoption(parser: pytest.Parser): """Add command-line options to pytest.""" @@ -98,6 +96,7 @@ class Alloc(BaseAlloc): _contract_address_iterator: Iterator[Address] = PrivateAttr() _eoa_iterator: Iterator[EOA] = PrivateAttr() _evm_code_type: EVMCodeType | None = PrivateAttr(None) + _fork: Fork = PrivateAttr() def __init__( self, @@ -105,6 +104,7 @@ def __init__( alloc_mode: AllocMode, contract_address_iterator: Iterator[Address], eoa_iterator: Iterator[EOA], + fork: Fork, evm_code_type: EVMCodeType | None = None, **kwargs, ): @@ -114,6 +114,7 @@ def __init__( self._contract_address_iterator = contract_address_iterator self._eoa_iterator = eoa_iterator self._evm_code_type = evm_code_type + self._fork = fork def __setitem__(self, address: Address | FixedSizeBytesConvertible, account: Account | None): """Set account associated with an address.""" @@ -166,8 +167,9 @@ def deploy_contract( code = self.code_pre_processor(code, evm_code_type=evm_code_type) code_bytes = bytes(code) if not isinstance(code, (bytes, str)) else code - assert len(code_bytes) <= MAX_BYTECODE_SIZE, ( - f"code too large: {len(code_bytes)} > {MAX_BYTECODE_SIZE}" + max_code_size = self._fork.max_code_size() + assert len(code_bytes) <= max_code_size, ( + f"code too large: {len(code_bytes)} > {max_code_size}" ) super().__setitem__( @@ -424,11 +426,13 @@ def pre( contract_address_iterator: Iterator[Address], eoa_iterator: Iterator[EOA], evm_code_type: EVMCodeType, + fork: Fork, ) -> Alloc: """Return default pre allocation for all tests (Empty alloc).""" return Alloc( alloc_mode=alloc_mode, contract_address_iterator=contract_address_iterator, eoa_iterator=eoa_iterator, + fork=fork, evm_code_type=evm_code_type, ) diff --git a/src/pytest_plugins/filler/tests/test_pre_alloc.py b/src/pytest_plugins/filler/tests/test_pre_alloc.py index e7c09a64255..05e6d80e188 100644 --- a/src/pytest_plugins/filler/tests/test_pre_alloc.py +++ b/src/pytest_plugins/filler/tests/test_pre_alloc.py @@ -5,6 +5,7 @@ import pytest from ethereum_test_base_types import Address, TestPrivateKey, TestPrivateKey2 +from ethereum_test_forks import Prague from ethereum_test_types import EOA from ethereum_test_vm import EVMCodeType from ethereum_test_vm import Opcodes as Op @@ -33,6 +34,7 @@ def create_test_alloc( alloc_mode=alloc_mode, contract_address_iterator=contract_iter, eoa_iterator=eoa_iter, + fork=Prague, evm_code_type=evm_code_type, ) From 04b73c53db19eb4390f47f30cfd53b37d7f52239 Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Fri, 3 Oct 2025 16:19:29 +0800 Subject: [PATCH 4/4] refactor: remove hardcoded value --- src/pytest_plugins/filler/tests/test_pre_alloc.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/pytest_plugins/filler/tests/test_pre_alloc.py b/src/pytest_plugins/filler/tests/test_pre_alloc.py index 05e6d80e188..ba7b9290d4f 100644 --- a/src/pytest_plugins/filler/tests/test_pre_alloc.py +++ b/src/pytest_plugins/filler/tests/test_pre_alloc.py @@ -5,7 +5,7 @@ import pytest from ethereum_test_base_types import Address, TestPrivateKey, TestPrivateKey2 -from ethereum_test_forks import Prague +from ethereum_test_forks import Fork, Prague from ethereum_test_types import EOA from ethereum_test_vm import EVMCodeType from ethereum_test_vm import Opcodes as Op @@ -19,7 +19,9 @@ def create_test_alloc( - alloc_mode: AllocMode = AllocMode.PERMISSIVE, evm_code_type: EVMCodeType = EVMCodeType.LEGACY + alloc_mode: AllocMode = AllocMode.PERMISSIVE, + fork: Fork = Prague, + evm_code_type: EVMCodeType = EVMCodeType.LEGACY, ) -> Alloc: """Create a test Alloc instance with default iterators.""" contract_iter = iter( @@ -34,7 +36,7 @@ def create_test_alloc( alloc_mode=alloc_mode, contract_address_iterator=contract_iter, eoa_iterator=eoa_iter, - fork=Prague, + fork=fork, evm_code_type=evm_code_type, )