From 9c87676c3fa37abd43b6814e46125b4eb922907b Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Thu, 25 Sep 2025 14:05:13 +0800 Subject: [PATCH 01/18] refactor(benchmark): update code generator interface --- .../benchmark_code_generator.py | 20 ++++++++++--------- src/ethereum_test_specs/benchmark.py | 11 +++++----- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/ethereum_test_benchmark/benchmark_code_generator.py b/src/ethereum_test_benchmark/benchmark_code_generator.py index 5781a8e474c..b81af44cf5a 100644 --- a/src/ethereum_test_benchmark/benchmark_code_generator.py +++ b/src/ethereum_test_benchmark/benchmark_code_generator.py @@ -3,6 +3,7 @@ optimized bytecode patterns. """ +from ethereum_test_base_types import Address from ethereum_test_forks import Fork from ethereum_test_specs.benchmark import BenchmarkCodeGenerator from ethereum_test_types import Alloc, Transaction @@ -13,18 +14,18 @@ class JumpLoopGenerator(BenchmarkCodeGenerator): """Generates bytecode that loops execution using JUMP operations.""" - def deploy_contracts(self, pre: Alloc, fork: Fork) -> None: + def deploy_contracts(self, pre: Alloc, fork: Fork) -> Address: """Deploy the looping contract.""" # Benchmark Test Structure: - # setup + JUMPDEST + attack + attack + ... + - # attack + JUMP(setup_length) - code = self.generate_repeated_code(self.attack_block, self.setup, fork) + # setup + JUMPDEST + attack + attack + ... + cleanup + JUMP(setup_length) + code = self.generate_repeated_code(self.attack_block, self.setup, self.cleanup, fork) self._contract_address = pre.deploy_contract(code=code) + return self._contract_address def generate_transaction(self, pre: Alloc, gas_limit: int) -> Transaction: """Generate transaction that executes the looping contract.""" if not hasattr(self, "_contract_address"): - raise ValueError("deploy_contracts must be called before generate_transaction") + self.deploy_contracts(pre, fork) return Transaction( to=self._contract_address, @@ -39,7 +40,7 @@ class ExtCallGenerator(BenchmarkCodeGenerator): maximum allowed code size. """ - def deploy_contracts(self, pre: Alloc, fork: Fork) -> None: + def deploy_contracts(self, pre: Alloc, fork: Fork) -> Address: """Deploy both target and caller contracts.""" # Benchmark Test Structure: # There are two contracts: @@ -53,7 +54,7 @@ def deploy_contracts(self, pre: Alloc, fork: Fork) -> None: # Deploy target contract that contains the actual attack block self._target_contract_address = pre.deploy_contract( - code=self.attack_block * max_iterations + code=self.setup + self.attack_block * max_iterations ) # Create caller contract that repeatedly calls the target contract @@ -65,13 +66,14 @@ def deploy_contracts(self, pre: Alloc, fork: Fork) -> None: # JUMP(setup_length) code_sequence = Op.POP(Op.STATICCALL(Op.GAS, self._target_contract_address, 0, 0, 0, 0)) - caller_code = self.generate_repeated_code(code_sequence, Bytecode(), fork) + caller_code = self.generate_repeated_code(code_sequence, Bytecode(), self.cleanup, fork) self._contract_address = pre.deploy_contract(code=caller_code) + return self._contract_address def generate_transaction(self, pre: Alloc, gas_limit: int) -> Transaction: """Generate transaction that executes the caller contract.""" if not hasattr(self, "_contract_address"): - raise ValueError("deploy_contracts must be called before generate_transaction") + self.deploy_contracts(pre, fork) return Transaction( to=self._contract_address, diff --git a/src/ethereum_test_specs/benchmark.py b/src/ethereum_test_specs/benchmark.py index fbcb5cba598..d0b2fcd14e1 100644 --- a/src/ethereum_test_specs/benchmark.py +++ b/src/ethereum_test_specs/benchmark.py @@ -9,7 +9,7 @@ from pydantic import ConfigDict, Field from ethereum_clis import TransitionTool -from ethereum_test_base_types import HexNumber +from ethereum_test_base_types import Address, HexNumber from ethereum_test_exceptions import BlockException, TransactionException from ethereum_test_execution import ( BaseExecute, @@ -40,9 +40,10 @@ class BenchmarkCodeGenerator(ABC): attack_block: Bytecode setup: Bytecode = field(default_factory=Bytecode) + cleanup: Bytecode = field(default_factory=Bytecode) @abstractmethod - def deploy_contracts(self, pre: Alloc, fork: Fork) -> None: + def deploy_contracts(self, pre: Alloc, fork: Fork) -> Address: """Deploy any contracts needed for the benchmark.""" ... @@ -52,7 +53,7 @@ def generate_transaction(self, pre: Alloc, gas_limit: int) -> Transaction: ... def generate_repeated_code( - self, repeated_code: Bytecode, setup: Bytecode, fork: Fork + self, repeated_code: Bytecode, setup: Bytecode, cleanup: Bytecode, fork: Fork ) -> Bytecode: """ Calculate the maximum number of iterations that @@ -61,11 +62,11 @@ def generate_repeated_code( assert len(repeated_code) > 0, "repeated_code cannot be empty" max_code_size = fork.max_code_size() - overhead = len(setup) + len(Op.JUMPDEST) + len(Op.JUMP(len(setup))) + overhead = len(setup) + len(Op.JUMPDEST) + len(cleanup) + len(Op.JUMP(len(setup))) available_space = max_code_size - overhead max_iterations = available_space // len(repeated_code) - code = setup + Op.JUMPDEST + repeated_code * max_iterations + Op.JUMP(len(setup)) + code = setup + Op.JUMPDEST + repeated_code * max_iterations + cleanup + Op.JUMP(len(setup)) self._validate_code_size(code, fork) return code From eec1199bdec7950a8863eb9b63af0bf2390346bf Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Thu, 25 Sep 2025 14:05:37 +0800 Subject: [PATCH 02/18] refactor(benchmark): update worst bytecode scenario --- tests/benchmark/test_worst_bytecode.py | 65 +++++++++----------------- 1 file changed, 23 insertions(+), 42 deletions(-) diff --git a/tests/benchmark/test_worst_bytecode.py b/tests/benchmark/test_worst_bytecode.py index 6340b2c49e4..85c2c49c405 100755 --- a/tests/benchmark/test_worst_bytecode.py +++ b/tests/benchmark/test_worst_bytecode.py @@ -6,16 +6,18 @@ import pytest +from ethereum_test_benchmark.benchmark_code_generator import JumpLoopGenerator from ethereum_test_forks import Fork from ethereum_test_tools import ( Account, Alloc, + BenchmarkTestFiller, Block, BlockchainTestFiller, Bytecode, + Bytes, Environment, Hash, - StateTestFiller, Transaction, While, compute_create2_address, @@ -23,8 +25,6 @@ from ethereum_test_types.helpers import compute_create_address from ethereum_test_vm import Opcodes as Op -from .helpers import code_loop_precompile_call - REFERENCE_SPEC_GIT_PATH = "TODO" REFERENCE_SPEC_VERSION = "TODO" @@ -245,7 +245,7 @@ def test_worst_bytecode_single_opcode( ids=lambda x: x.hex(), ) def test_worst_initcode_jumpdest_analysis( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, pattern: Bytecode, @@ -261,7 +261,6 @@ def test_worst_initcode_jumpdest_analysis( is modified by mixing-in the returned create address between CREATE invocations to prevent caching. """ - max_code_size = fork.max_code_size() initcode_size = fork.max_initcode_size() # Expand the initcode pattern to the transaction data so it can be used in @@ -291,32 +290,20 @@ def test_worst_initcode_jumpdest_analysis( # Make sure the last opcode in the initcode is JUMPDEST. code_prepare_initcode += Op.MSTORE(initcode_size - 32, Op.PUSH32[bytes(Op.JUMPDEST) * 32]) - code_invoke_create = ( + attack_block = ( Op.PUSH1[len(initcode_prefix)] + Op.MSTORE + Op.CREATE(value=Op.PUSH0, offset=Op.PUSH0, size=Op.MSIZE) ) - initial_random = Op.PUSH0 - code_prefix = code_prepare_initcode + initial_random - code_loop_header = Op.JUMPDEST - code_loop_footer = Op.JUMP(len(code_prefix)) - code_loop_body_len = ( - max_code_size - len(code_prefix) - len(code_loop_header) - len(code_loop_footer) - ) - - code_loop_body = (code_loop_body_len // len(code_invoke_create)) * bytes(code_invoke_create) - code = code_prefix + code_loop_header + code_loop_body + code_loop_footer - assert (max_code_size - len(code_invoke_create)) < len(code) <= max_code_size + setup = code_prepare_initcode + Op.PUSH0 - tx = Transaction( - to=pre.deploy_contract(code=code), - data=tx_data, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) + tx = JumpLoopGenerator( + setup=setup, attack_block=attack_block, cleanup=Bytecode() + ).generate_transaction(pre, gas_benchmark_value, fork) + tx.data = Bytes(tx_data) - state_test( + benchmark_test( pre=pre, post={}, tx=tx, @@ -349,7 +336,7 @@ def test_worst_initcode_jumpdest_analysis( ], ) def test_worst_create( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, opcode: Op, @@ -394,7 +381,7 @@ def test_worst_create( # ... # JUMP(#) # ``` - code_prefix = ( + setup = ( Op.PUSH3(code_size) + Op.PUSH1(value) + Op.EXTCODECOPY( @@ -405,7 +392,7 @@ def test_worst_create( if opcode == Op.CREATE2: # For CREATE2, we provide an initial salt. - code_prefix = code_prefix + Op.PUSH1(42) + setup += Op.PUSH1(42) attack_block = ( # For CREATE: @@ -420,16 +407,18 @@ def test_worst_create( # - DUP3 is targeting the EXTCODESIZE value pushed in code_prefix. else Op.DUP3 + Op.PUSH0 + Op.DUP4 + Op.CREATE2 ) - code = code_loop_precompile_call(code_prefix, attack_block, fork) + + code = JumpLoopGenerator(setup=setup, attack_block=attack_block).generate_repeated_code( + attack_block, Bytecode(), Bytecode(), fork + ) tx = Transaction( # Set enough balance in the pre-alloc for `value > 0` configurations. to=pre.deploy_contract(code=code, balance=1_000_000_000 if value > 0 else 0), - gas_limit=gas_benchmark_value, sender=pre.fund_eoa(), ) - state_test( + benchmark_test( pre=pre, post={}, tx=tx, @@ -444,7 +433,7 @@ def test_worst_create( ], ) def test_worst_creates_collisions( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, opcode: Op, @@ -475,14 +464,12 @@ def test_worst_creates_collisions( # The CALL to the proxy contract needs at a minimum gas corresponding to # the CREATE(2) plus extra required PUSH0s for arguments. min_gas_required = gas_costs.G_CREATE + gas_costs.G_BASE * (3 if opcode == Op.CREATE else 4) - code_prefix = Op.PUSH20(proxy_contract) + Op.PUSH3(min_gas_required) + setup = Op.PUSH20(proxy_contract) + Op.PUSH3(min_gas_required) attack_block = Op.POP( # DUP7 refers to the PUSH3 above. # DUP7 refers to the proxy contract address. Op.CALL(gas=Op.DUP7, address=Op.DUP7) ) - code = code_loop_precompile_call(code_prefix, attack_block, fork) - tx_target = pre.deploy_contract(code=code) # (**) We deploy the contract that CREATE(2) will attempt to create so any # attempt will fail. @@ -496,14 +483,8 @@ def test_worst_creates_collisions( addr = compute_create_address(address=proxy_contract, nonce=nonce) pre.deploy_contract(address=addr, code=Op.INVALID) - tx = Transaction( - to=tx_target, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( + benchmark_test( pre=pre, post={}, - tx=tx, + code_generator=JumpLoopGenerator(setup=setup, attack_block=attack_block), ) From a99e58a065b864f9507392ceb794753c46bc6ee2 Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Thu, 25 Sep 2025 14:06:00 +0800 Subject: [PATCH 03/18] refactor(benchmark): update worst compute scenario --- tests/benchmark/test_worst_compute.py | 709 +++++++------------------- 1 file changed, 179 insertions(+), 530 deletions(-) diff --git a/tests/benchmark/test_worst_compute.py b/tests/benchmark/test_worst_compute.py index 7f4d132892c..2d62d90235e 100755 --- a/tests/benchmark/test_worst_compute.py +++ b/tests/benchmark/test_worst_compute.py @@ -11,18 +11,16 @@ import pytest from py_ecc.bn128 import G1, G2, multiply -from ethereum_test_base_types.base_types import Bytes -from ethereum_test_benchmark.benchmark_code_generator import JumpLoopGenerator +from ethereum_test_base_types.base_types import Bytes, HexNumber +from ethereum_test_benchmark import ExtCallGenerator, JumpLoopGenerator from ethereum_test_forks import Fork from ethereum_test_tools import ( Address, Alloc, BenchmarkTestFiller, Block, - BlockchainTestFiller, Bytecode, Environment, - StateTestFiller, Transaction, add_kzg_version, ) @@ -38,7 +36,6 @@ from ..osaka.eip7951_p256verify_precompiles.spec import FieldElement from ..prague.eip2537_bls_12_381_precompiles import spec as bls12381_spec from ..prague.eip2537_bls_12_381_precompiles.spec import BytesConcatenation -from .helpers import code_loop_precompile_call REFERENCE_SPEC_GIT_PATH = "TODO" REFERENCE_SPEC_VERSION = "TODO" @@ -82,60 +79,35 @@ def make_dup(index: int) -> Opcode: ], ) def test_worst_zero_param( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, opcode: Op, fork: Fork, gas_benchmark_value: int, ) -> None: """Test running a block with as many zero-parameter opcodes as possible.""" - opcode_sequence = opcode * fork.max_stack_height() - target_contract_address = pre.deploy_contract(code=opcode_sequence) - - 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( - to=code_address, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( + benchmark_test( pre=pre, post={}, - tx=tx, + code_generator=ExtCallGenerator(setup=Bytecode(), attack_block=opcode), ) @pytest.mark.parametrize("calldata_length", [0, 1_000, 10_000]) def test_worst_calldatasize( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, calldata_length: int, gas_benchmark_value: int, ) -> None: """Test running a block with as many CALLDATASIZE as possible.""" - max_code_size = fork.max_code_size() + tx = JumpLoopGenerator( + setup=Bytecode(), attack_block=Op.POP(Op.CALLDATASIZE) + ).generate_transaction(pre, gas_benchmark_value, fork) + tx.data = Bytes(b"\x00" * calldata_length) - code_prefix = Op.JUMPDEST - iter_loop = Op.POP(Op.CALLDATASIZE) - code_suffix = Op.PUSH0 + Op.JUMP - code_iter_len = (max_code_size - len(code_prefix) - len(code_suffix)) // len(iter_loop) - code = code_prefix + iter_loop * code_iter_len + code_suffix - assert len(code) <= max_code_size - - tx = Transaction( - to=pre.deploy_contract(code=bytes(code)), - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - data=b"\x00" * calldata_length, - ) - - state_test( + benchmark_test( pre=pre, post={}, tx=tx, @@ -145,7 +117,7 @@ def test_worst_calldatasize( @pytest.mark.parametrize("non_zero_value", [True, False]) @pytest.mark.parametrize("from_origin", [True, False]) def test_worst_callvalue( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, non_zero_value: bool, @@ -159,15 +131,9 @@ def test_worst_callvalue( value. The `from_origin` parameter controls whether the call frame is the immediate from the transaction or a previous CALL. """ - max_code_size = fork.max_code_size() - - code_prefix = Op.JUMPDEST - iter_loop = Op.POP(Op.CALLVALUE) - code_suffix = Op.PUSH0 + Op.JUMP - code_iter_len = (max_code_size - len(code_prefix) - len(code_suffix)) // len(iter_loop) - code = code_prefix + iter_loop * code_iter_len + code_suffix - assert len(code) <= max_code_size - code_address = pre.deploy_contract(code=bytes(code)) + code_address = JumpLoopGenerator( + setup=Bytecode(), attack_block=Op.POP(Op.CALLVALUE), cleanup=Bytecode() + ).deploy_contracts(pre, fork) if from_origin: tx_to = code_address @@ -181,12 +147,11 @@ def test_worst_callvalue( tx = Transaction( to=tx_to, - gas_limit=gas_benchmark_value, value=1 if non_zero_value and from_origin else 0, sender=pre.fund_eoa(), ) - state_test( + benchmark_test( pre=pre, post={}, tx=tx, @@ -211,9 +176,8 @@ class ReturnDataStyle(Enum): ) @pytest.mark.parametrize("returned_size", [1, 0]) def test_worst_returndatasize_nonzero( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, - fork: Fork, returned_size: int, return_data_style: ReturnDataStyle, gas_benchmark_value: int, @@ -226,11 +190,9 @@ def test_worst_returndatasize_nonzero( buffer. The `return_data_style` indicates how returned data is produced for the opcode caller. """ - max_code_size = fork.max_code_size() - - dummy_contract_call = Bytecode() + setup = Bytecode() if return_data_style != ReturnDataStyle.IDENTITY: - dummy_contract_call = Op.STATICCALL( + setup += Op.STATICCALL( address=pre.deploy_contract( code=Op.REVERT(0, returned_size) if return_data_style == ReturnDataStyle.REVERT @@ -238,33 +200,20 @@ def test_worst_returndatasize_nonzero( ) ) else: - dummy_contract_call = Op.MSTORE8(0, 1) + Op.STATICCALL( + setup += Op.MSTORE8(0, 1) + Op.STATICCALL( address=0x04, # Identity precompile args_size=returned_size, ) - code_prefix = dummy_contract_call + Op.JUMPDEST - iter_loop = Op.POP(Op.RETURNDATASIZE) - code_suffix = Op.JUMP(len(code_prefix) - 1) - code_iter_len = (max_code_size - len(code_prefix) - len(code_suffix)) // len(iter_loop) - code = code_prefix + iter_loop * code_iter_len + code_suffix - assert len(code) <= max_code_size - - tx = Transaction( - to=pre.deploy_contract(code=bytes(code)), - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( + benchmark_test( pre=pre, post={}, - tx=tx, + code_generator=JumpLoopGenerator(setup=setup, attack_block=Op.POP(Op.RETURNDATASIZE)), ) def test_worst_returndatasize_zero( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, gas_benchmark_value: int, @@ -293,13 +242,13 @@ def test_worst_returndatasize_zero( state_test( pre=pre, post={}, - tx=tx, + code_generator=ExtCallGenerator(setup=Bytecode(), attack_block=Op.RETURNDATASIZE), ) @pytest.mark.parametrize("mem_size", [0, 1, 1_000, 100_000, 1_000_000]) def test_worst_msize( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, mem_size: int, @@ -310,26 +259,15 @@ def test_worst_msize( The `mem_size` parameter indicates by how much the memory is expanded. """ - max_stack_height = fork.max_stack_height() - - code_sequence = Op.MLOAD(Op.CALLVALUE) + Op.POP + Op.MSIZE * max_stack_height - target_address = pre.deploy_contract(code=code_sequence) - - calldata = Bytecode() - attack_block = Op.POP(Op.STATICCALL(Op.GAS, target_address, 0, 0, 0, 0)) - code = code_loop_precompile_call(calldata, attack_block, fork) - assert len(code) <= fork.max_code_size() - - code_address = pre.deploy_contract(code=code) - - tx = Transaction( - to=code_address, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - value=mem_size, + generator = ExtCallGenerator( + setup=Op.MLOAD(Op.CALLVALUE) + Op.POP, + attack_block=Op.MSIZE, ) + generator.deploy_contracts(pre, fork) + tx = generator.generate_transaction(pre, gas_benchmark_value, fork) + tx.value = HexNumber(mem_size) - state_test( + benchmark_test( pre=pre, post={}, tx=tx, @@ -337,7 +275,7 @@ def test_worst_msize( def test_worst_keccak( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, gas_benchmark_value: int, @@ -350,11 +288,8 @@ def test_worst_keccak( gsc = fork.gas_costs() mem_exp_gas_calculator = fork.memory_expansion_gas_calculator() - max_code_size = fork.max_code_size() - - # Discover the optimal input size to maximize keccak-permutations, not - # keccak calls. The complication of the discovery arises from the non- - # linear gas cost of memory expansion. + # Discover the optimal input size to maximize keccak-permutations, not keccak calls. + # The complication of the discovery arises from the non-linear gas cost of memory expansion. max_keccak_perm_per_block = 0 optimal_input_length = 0 for i in range(1, 1_000_000, 32): @@ -385,32 +320,18 @@ def test_worst_keccak( # The loop structure is: JUMPDEST + [attack iteration] + PUSH0 + JUMP # # Now calculate available gas for [attack iteration]: - # Numerator = max_code_size-3. The -3 is for the JUMPDEST, PUSH0 and JUMP - # Denominator = (PUSHN + PUSH1 + KECCAK256 + POP) + PUSH1_DATA + PUSHN_DATA - # - # TODO: the testing framework uses PUSH1(0) instead of PUSH0 which is - # suboptimal for the attack, whenever this is fixed adjust accordingly. - start_code = Op.JUMPDEST + Op.PUSH20[optimal_input_length] - loop_code = Op.POP(Op.SHA3(Op.PUSH0, Op.DUP1)) - end_code = Op.POP + Op.JUMP(Op.PUSH0) - max_iters_loop = (max_code_size - (len(start_code) + len(end_code))) // len(loop_code) - code = start_code + (loop_code * max_iters_loop) + end_code - if len(code) > max_code_size: - # Must never happen, but keep it as a sanity check. - raise ValueError(f"Code size {len(code)} exceeds maximum code size {max_code_size}") - - code_address = pre.deploy_contract(code=bytes(code)) - - tx = Transaction( - to=code_address, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( + # Numerator = max_code_size-3. The -3 is for the JUMPDEST, PUSH0 and JUMP. + # Denominator = (PUSHN + PUSH1 + KECCAK256 + POP) + PUSH1_DATA + PUSHN_DATA + # TODO: the testing framework uses PUSH1(0) instead of PUSH0 which is suboptimal for the + # attack, whenever this is fixed adjust accordingly. + benchmark_test( pre=pre, post={}, - tx=tx, + code_generator=JumpLoopGenerator( + setup=Op.PUSH20[optimal_input_length], + attack_block=Op.POP(Op.SHA3(Op.PUSH0, Op.DUP1)), + cleanup=Bytecode(), + ), ) @@ -423,7 +344,7 @@ def test_worst_keccak( ], ) def test_worst_precompile_only_data_input( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, address: Address, @@ -478,22 +399,14 @@ def test_worst_precompile_only_data_input( max_work = total_work optimal_input_length = input_length - calldata = Op.CODECOPY(0, 0, optimal_input_length) attack_block = Op.POP(Op.STATICCALL(Op.GAS, address, 0, optimal_input_length, 0, 0)) - code = code_loop_precompile_call(calldata, attack_block, fork) - code_address = pre.deploy_contract(code=code) - - tx = Transaction( - to=code_address, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( + benchmark_test( pre=pre, post={}, - tx=tx, + code_generator=JumpLoopGenerator( + setup=Op.CODECOPY(0, 0, optimal_input_length), attack_block=attack_block + ), ) @@ -1327,7 +1240,7 @@ def test_worst_precompile_only_data_input( ], ) def test_worst_modexp( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, mod_exp_input: ModExpInput, @@ -1337,24 +1250,16 @@ def test_worst_modexp( Test running a block with as many calls to the MODEXP (5) precompile as possible. All the calls have the same parametrized input. """ - # Skip the trailing zeros from the input to make EVM work even harder. - calldata = bytes(mod_exp_input).rstrip(b"\x00") - - code = code_loop_precompile_call( - Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE), # Copy the input to the - # memory. - Op.POP(Op.STATICCALL(Op.GAS, 0x5, Op.PUSH0, Op.CALLDATASIZE, Op.PUSH0, Op.PUSH0)), - fork, + attack_block = Op.POP( + Op.STATICCALL(Op.GAS, 0x5, Op.PUSH0, Op.CALLDATASIZE, Op.PUSH0, Op.PUSH0) ) - tx = Transaction( - to=pre.deploy_contract(code=code), - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - input=calldata, - ) + tx = JumpLoopGenerator( + setup=Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE), attack_block=attack_block + ).generate_transaction(pre, gas_benchmark_value, fork) + tx.data = Bytes(bytes(mod_exp_input).rstrip(b"\x00")) - state_test( + benchmark_test( pre=pre, post={}, tx=tx, @@ -1786,7 +1691,7 @@ def test_worst_modexp( ], ) def test_worst_precompile_fixed_cost( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, precompile_address: Address, @@ -1816,47 +1721,34 @@ def test_worst_precompile_fixed_cost( padding_length = (32 - (len(concatenated_bytes) % 32)) % 32 input_bytes = concatenated_bytes + b"\x00" * padding_length - calldata = Bytecode() + setup = Bytecode() for i in range(0, len(input_bytes), 32): chunk = input_bytes[i : i + 32] value_to_store = int.from_bytes(chunk, "big") - calldata += Op.MSTORE(i, value_to_store) + setup += Op.MSTORE(i, value_to_store) attack_block = Op.POP( Op.STATICCALL(Op.GAS, precompile_address, 0, len(concatenated_bytes), 0, 0) ) - code = code_loop_precompile_call(calldata, attack_block, fork) - code_address = pre.deploy_contract(code=bytes(code)) - tx = Transaction( - to=code_address, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( + benchmark_test( pre=pre, post={}, - tx=tx, + code_generator=JumpLoopGenerator(setup=setup, attack_block=attack_block), ) def test_worst_jumps( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, - gas_benchmark_value: int, ) -> None: """Test running a JUMP-intensive contract.""" - jumps_code = Op.JUMPDEST + Op.JUMP(Op.PUSH0) - jumps_address = pre.deploy_contract(jumps_code) - tx = Transaction( - to=jumps_address, - gas_limit=gas_benchmark_value, + to=pre.deploy_contract(code=(Op.JUMPDEST + Op.JUMP(Op.PUSH0))), sender=pre.fund_eoa(), ) - state_test( + benchmark_test( pre=pre, post={}, tx=tx, @@ -1864,64 +1756,36 @@ def test_worst_jumps( def test_worst_jumpi_fallthrough( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, - fork: Fork, - gas_benchmark_value: int, ) -> None: """Test running a JUMPI-intensive contract with fallthrough.""" - max_code_size = fork.max_code_size() - - def jumpi_seq() -> Bytecode: - return Op.JUMPI(Op.PUSH0, Op.PUSH0) - - prefix_seq = Op.JUMPDEST - suffix_seq = Op.JUMP(Op.PUSH0) - bytes_per_seq = len(jumpi_seq()) - seqs_per_call = (max_code_size - len(prefix_seq) - len(suffix_seq)) // bytes_per_seq - - # Create and deploy the jumpi-intensive contract - jumpis_code = prefix_seq + jumpi_seq() * seqs_per_call + suffix_seq - assert len(jumpis_code) <= max_code_size - - jumpis_address = pre.deploy_contract(code=bytes(jumpis_code)) - - tx = Transaction( - to=jumpis_address, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( + benchmark_test( pre=pre, post={}, - tx=tx, + code_generator=JumpLoopGenerator( + setup=Bytecode(), attack_block=Op.JUMPI(Op.PUSH0, Op.PUSH0) + ), ) def test_worst_jumpis( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, - gas_benchmark_value: int, ) -> None: """Test running a JUMPI-intensive contract.""" - jumpi_code = Op.JUMPDEST + Op.JUMPI(Op.PUSH0, Op.NUMBER) - jumpi_address = pre.deploy_contract(jumpi_code) - tx = Transaction( - to=jumpi_address, - gas_limit=gas_benchmark_value, + to=pre.deploy_contract(code=(Op.JUMPDEST + Op.JUMPI(Op.PUSH0, Op.NUMBER))), sender=pre.fund_eoa(), ) - state_test( + benchmark_test( pre=pre, post={}, tx=tx, ) -@pytest.mark.slow def test_worst_jumpdests( benchmark_test: BenchmarkTestFiller, pre: Alloc, @@ -2083,7 +1947,7 @@ def test_worst_jumpdests( ids=lambda param: "" if isinstance(param, tuple) else param, ) def test_worst_binop_simple( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, opcode: Op, fork: Fork, @@ -2095,25 +1959,17 @@ def test_worst_binop_simple( produces one value) as possible. The execution starts with two initial values on the stack, and the stack is balanced by the DUP2 instruction. """ - max_code_size = fork.max_code_size() - tx_data = b"".join(arg.to_bytes(32, byteorder="big") for arg in opcode_args) - code_prefix = Op.JUMPDEST + Op.CALLDATALOAD(0) + Op.CALLDATALOAD(32) - code_suffix = Op.POP + Op.POP + Op.PUSH0 + Op.JUMP - code_body_len = max_code_size - len(code_prefix) - len(code_suffix) - code_body = (Op.DUP2 + opcode) * (code_body_len // 2) - code = code_prefix + code_body + code_suffix - assert len(code) == max_code_size - 1 - - tx = Transaction( - to=pre.deploy_contract(code=code), - data=tx_data, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) + setup = Op.CALLDATALOAD(0) + Op.CALLDATALOAD(32) + Op.DUP2 + Op.DUP2 + attack_block = Op.DUP2 + opcode + cleanup = Op.POP + Op.POP + tx = JumpLoopGenerator( + setup=setup, attack_block=attack_block, cleanup=cleanup + ).generate_transaction(pre, gas_benchmark_value, fork) + tx.data = Bytes(tx_data) - state_test( + benchmark_test( pre=pre, post={}, tx=tx, @@ -2122,35 +1978,20 @@ def test_worst_binop_simple( @pytest.mark.parametrize("opcode", [Op.ISZERO, Op.NOT]) def test_worst_unop( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, opcode: Op, - fork: Fork, - gas_benchmark_value: int, ) -> None: """ Test running a block with as many unary instructions (takes one arg, produces one value) as possible. """ - max_code_size = fork.max_code_size() - - code_prefix = Op.JUMPDEST + Op.PUSH0 # Start with the arg 0. - code_suffix = Op.POP + Op.PUSH0 + Op.JUMP - code_body_len = max_code_size - len(code_prefix) - len(code_suffix) - code_body = opcode * code_body_len - code = code_prefix + code_body + code_suffix - assert len(code) == max_code_size - - tx = Transaction( - to=pre.deploy_contract(code=code), - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( + benchmark_test( pre=pre, post={}, - tx=tx, + code_generator=JumpLoopGenerator( + setup=Op.PUSH0, attack_block=opcode, cleanup=Op.POP + Op.PUSH0 + ), ) @@ -2160,7 +2001,7 @@ def test_worst_unop( # key changes. @pytest.mark.parametrize("val_mut", [True, False]) def test_worst_tload( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, fork: Fork, pre: Alloc, key_mut: bool, @@ -2168,43 +2009,31 @@ def test_worst_tload( gas_benchmark_value: int, ) -> None: """Test running a block with as many TLOAD calls as possible.""" - max_code_size = fork.max_code_size() - start_key = 41 code_key_mut = Bytecode() code_val_mut = Bytecode() + setup = Bytecode() if key_mut and val_mut: - code_prefix = Op.PUSH1(start_key) + Op.JUMPDEST - loop_iter = Op.POP(Op.TLOAD(Op.DUP1)) + setup = Op.PUSH1(start_key) + attack_block = Op.POP(Op.TLOAD(Op.DUP1)) code_key_mut = Op.POP + Op.GAS code_val_mut = Op.TSTORE(Op.DUP2, Op.GAS) if key_mut and not val_mut: - code_prefix = Op.JUMPDEST - loop_iter = Op.POP(Op.TLOAD(Op.GAS)) + attack_block = Op.POP(Op.TLOAD(Op.GAS)) if not key_mut and val_mut: - code_prefix = Op.JUMPDEST - loop_iter = Op.POP(Op.TLOAD(Op.CALLVALUE)) - code_val_mut = Op.TSTORE(Op.CALLVALUE, Op.GAS) # CALLVALUE configured - # in the tx + attack_block = Op.POP(Op.TLOAD(Op.CALLVALUE)) + code_val_mut = Op.TSTORE(Op.CALLVALUE, Op.GAS) # CALLVALUE configured in the tx if not key_mut and not val_mut: - code_prefix = Op.JUMPDEST - loop_iter = Op.POP(Op.TLOAD(Op.CALLVALUE)) + attack_block = Op.POP(Op.TLOAD(Op.CALLVALUE)) - code_suffix = code_key_mut + code_val_mut + Op.JUMP(len(code_prefix) - 1) + cleanup = code_key_mut + code_val_mut - code_body_len = (max_code_size - len(code_prefix) - len(code_suffix)) // len(loop_iter) - code_body = loop_iter * code_body_len - code = code_prefix + code_body + code_suffix - assert len(code) <= max_code_size + tx = JumpLoopGenerator( + setup=setup, attack_block=attack_block, cleanup=cleanup + ).generate_transaction(pre, gas_benchmark_value, fork) + tx.value = HexNumber(start_key if not key_mut and val_mut else 0) - tx = Transaction( - to=pre.deploy_contract(code), - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - value=start_key if not key_mut and val_mut else 0, - ) - - state_test( + benchmark_test( pre=pre, post={}, tx=tx, @@ -2214,49 +2043,32 @@ def test_worst_tload( @pytest.mark.parametrize("key_mut", [True, False]) @pytest.mark.parametrize("dense_val_mut", [True, False]) def test_worst_tstore( - state_test: StateTestFiller, - fork: Fork, + benchmark_test: BenchmarkTestFiller, pre: Alloc, key_mut: bool, dense_val_mut: bool, - gas_benchmark_value: int, -) -> None: +): """Test running a block with as many TSTORE calls as possible.""" - max_code_size = fork.max_code_size() - init_key = 42 - code_prefix = Op.PUSH1(init_key) + Op.JUMPDEST + setup = Op.PUSH1(init_key) - # If `key_mut` is True, we mutate the key on every iteration of the big - # loop. - code_key_mut = Op.POP + Op.GAS if key_mut else Bytecode() - code_suffix = code_key_mut + Op.JUMP(len(code_prefix) - 1) + # If `dense_val_mut` is set, we use GAS as a cheap way of always storing a different value than + # the previous one. + attack_block = Op.TSTORE(Op.DUP2, Op.GAS if dense_val_mut else Op.DUP1) - # If `dense_val_mut` is set, we use GAS as a cheap way of always storing a - # different value than the previous one. - loop_iter = Op.TSTORE(Op.DUP2, Op.GAS if dense_val_mut else Op.DUP1) + # If `key_mut` is True, we mutate the key on every iteration of the big loop. + cleanup = Op.POP + Op.GAS if key_mut else Bytecode() - code_body_len = (max_code_size - len(code_prefix) - len(code_suffix)) // len(loop_iter) - code_body = loop_iter * code_body_len - code = code_prefix + code_body + code_suffix - assert len(code) <= max_code_size - - tx = Transaction( - to=pre.deploy_contract(code), - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( + benchmark_test( pre=pre, post={}, - tx=tx, + code_generator=JumpLoopGenerator(setup=setup, attack_block=attack_block, cleanup=cleanup), ) @pytest.mark.parametrize("shift_right", [Op.SHR, Op.SAR]) def test_worst_shifts( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, shift_right: Op, @@ -2333,7 +2145,7 @@ def select_shift_amount(shift_fn: Any, v: Any) -> Any: sender=pre.fund_eoa(), ) - state_test( + benchmark_test( pre=pre, post={}, tx=tx, @@ -2351,52 +2163,26 @@ def select_shift_amount(shift_fn: Any, v: Any) -> Any: ) def test_worst_blobhash( fork: Fork, - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, blob_index: int, blobs_present: bool, gas_benchmark_value: int, ) -> None: """Test running a block with as many BLOBHASH instructions as possible.""" - max_code_size = fork.max_code_size() - max_stack_height = fork.max_stack_height() - - # Contract that contains a collection of BLOBHASH instructions. - opcode_sequence = Op.BLOBHASH(blob_index) * max_stack_height - assert len(opcode_sequence) <= max_code_size - - target_contract_address = pre.deploy_contract(code=opcode_sequence) + tx = ExtCallGenerator( + setup=Bytecode(), attack_block=Op.BLOBHASH(blob_index) + ).generate_transaction(pre, gas_benchmark_value, fork) - # Contract that contains a loop of STATICCALLs to the target contract. - 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) - assert len(code) <= max_code_size - - code_address = pre.deploy_contract(code=code) - - # Create blob transaction if blobs are present. - tx_type = TransactionType.LEGACY - blob_versioned_hashes = None - max_fee_per_blob_gas = None if blobs_present > 0: - tx_type = TransactionType.BLOB_TRANSACTION - max_fee_per_blob_gas = fork.min_base_fee_per_blob_gas() - blob_versioned_hashes = add_kzg_version( + tx.ty = HexNumber(TransactionType.BLOB_TRANSACTION) + tx.max_fee_per_blob_gas = HexNumber(fork.min_base_fee_per_blob_gas()) + tx.blob_versioned_hashes = add_kzg_version( [i.to_bytes() * 32 for i in range(blobs_present)], BlobsSpec.BLOB_COMMITMENT_VERSION_KZG, ) - tx = Transaction( - ty=tx_type, - to=code_address, - gas_limit=gas_benchmark_value, - max_fee_per_blob_gas=max_fee_per_blob_gas, - blob_versioned_hashes=blob_versioned_hashes, - sender=pre.fund_eoa(), - ) - - state_test( + benchmark_test( pre=pre, post={}, tx=tx, @@ -2406,7 +2192,7 @@ def test_worst_blobhash( @pytest.mark.parametrize("mod_bits", [255, 191, 127, 63]) @pytest.mark.parametrize("op", [Op.MOD, Op.SMOD]) def test_worst_mod( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, mod_bits: int, @@ -2428,11 +2214,9 @@ def test_worst_mod( The order of accessing the numerators is selected in a way the mod value remains in the range as long as possible. """ - max_code_size = fork.max_code_size() - - # For SMOD we negate both numerator and modulus. The underlying computation - # is the same, just the SMOD implementation will have to additionally - # handle the sign bits. The result stays negative. + # For SMOD we negate both numerator and modulus. The underlying computation is the same, + # just the SMOD implementation will have to additionally handle the sign bits. + # The result stays negative. should_negate = op == Op.SMOD num_numerators = 15 @@ -2503,32 +2287,20 @@ def test_worst_mod( seed += 1 print(f"{seed=}") - # TODO: Don't use fixed PUSH32. Let Bytecode helpers to select optimal push - # opcode. - code_constant_pool = sum((Op.PUSH32[n] for n in numerators), Bytecode()) - code_prefix = code_constant_pool + Op.JUMPDEST - code_suffix = Op.JUMP(len(code_constant_pool)) - code_body_len = max_code_size - len(code_prefix) - len(code_suffix) - code_segment = ( + # TODO: Don't use fixed PUSH32. Let Bytecode helpers to select optimal push opcode. + setup = sum((Op.PUSH32[n] for n in numerators), Bytecode()) + attack_block = ( Op.CALLDATALOAD(0) + sum(make_dup(len(numerators) - i) + op for i in indexes) + Op.POP ) - code = ( - code_prefix - # TODO: Add int * Bytecode support - + sum(code_segment for _ in range(code_body_len // len(code_segment))) - + code_suffix + + tx = JumpLoopGenerator(setup=setup, attack_block=attack_block).generate_transaction( + pre, gas_benchmark_value, fork ) - assert (max_code_size - len(code_segment)) < len(code) <= max_code_size input_value = initial_mod if not should_negate else neg(initial_mod) - tx = Transaction( - to=pre.deploy_contract(code=code), - data=input_value.to_bytes(32, byteorder="big"), - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) + tx.data = Bytes(input_value.to_bytes(32, byteorder="big")) - state_test( + benchmark_test( pre=pre, post={}, tx=tx, @@ -2540,50 +2312,31 @@ def test_worst_mod( @pytest.mark.parametrize("offset_initialized", [True, False]) @pytest.mark.parametrize("big_memory_expansion", [True, False]) def test_worst_memory_access( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, - fork: Fork, opcode: Op, offset: int, offset_initialized: bool, big_memory_expansion: bool, - gas_benchmark_value: int, ) -> None: - """ - Test running a block with as many memory access instructions as possible. - """ - max_code_size = fork.max_code_size() - + """Test running a block with as many memory access instructions as possible.""" mem_exp_code = Op.MSTORE8(10 * 1024, 1) if big_memory_expansion else Bytecode() offset_set_code = Op.MSTORE(offset, 43) if offset_initialized else Bytecode() - code_prefix = mem_exp_code + offset_set_code + Op.PUSH1(42) + Op.PUSH1(offset) + Op.JUMPDEST - - code_suffix = Op.JUMP(len(code_prefix) - 1) - - loop_iter = Op.POP(Op.MLOAD(Op.DUP1)) if opcode == Op.MLOAD else opcode(Op.DUP2, Op.DUP2) - - code_body_len = (max_code_size - len(code_prefix) - len(code_suffix)) // len(loop_iter) - code_body = loop_iter * code_body_len - code = code_prefix + code_body + code_suffix - assert len(code) <= max_code_size + setup = mem_exp_code + offset_set_code + Op.PUSH1(42) + Op.PUSH1(offset) - tx = Transaction( - to=pre.deploy_contract(code=code), - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) + attack_block = Op.POP(Op.MLOAD(Op.DUP1)) if opcode == Op.MLOAD else opcode(Op.DUP2, Op.DUP2) - state_test( + benchmark_test( pre=pre, post={}, - tx=tx, + code_generator=JumpLoopGenerator(setup=setup, attack_block=attack_block), ) @pytest.mark.parametrize("mod_bits", [255, 191, 127, 63]) @pytest.mark.parametrize("op", [Op.ADDMOD, Op.MULMOD]) def test_worst_modarith( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, mod_bits: int, @@ -2682,7 +2435,7 @@ def test_worst_modarith( sender=pre.fund_eoa(), ) - state_test( + benchmark_test( pre=pre, post={}, tx=tx, @@ -2690,11 +2443,11 @@ def test_worst_modarith( def test_empty_block( - blockchain_test: BlockchainTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, ) -> None: """Test running an empty block as a baseline for fixed proving costs.""" - blockchain_test( + benchmark_test( pre=pre, post={}, blocks=[Block(txs=[])], @@ -2703,7 +2456,7 @@ def test_empty_block( def test_amortized_bn128_pairings( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, gas_benchmark_value: int, @@ -2750,20 +2503,15 @@ def test_amortized_bn128_pairings( max_pairings = num_pairings_done optimal_per_call_num_pairings = i - calldata = Op.CALLDATACOPY(size=Op.CALLDATASIZE) + setup = Op.CALLDATACOPY(size=Op.CALLDATASIZE) attack_block = Op.POP(Op.STATICCALL(Op.GAS, 0x08, 0, Op.CALLDATASIZE, 0, 0)) - code = code_loop_precompile_call(calldata, attack_block, fork) - code_address = pre.deploy_contract(code=code) - - tx = Transaction( - to=code_address, - gas_limit=gas_benchmark_value, - data=_generate_bn128_pairs(optimal_per_call_num_pairings, 42), - sender=pre.fund_eoa(), + tx = JumpLoopGenerator(setup=setup, attack_block=attack_block).generate_transaction( + pre, gas_benchmark_value, fork ) + tx.data = _generate_bn128_pairs(optimal_per_call_num_pairings, 42) - state_test( + benchmark_test( pre=pre, post={}, tx=tx, @@ -2809,34 +2557,15 @@ def _generate_bn128_pairs(n: int, seed: int = 0) -> Bytes: ], ) def test_worst_calldataload( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, - fork: Fork, calldata: bytes, - gas_benchmark_value: int, -) -> None: +): """Test running a block with as many CALLDATALOAD as possible.""" - max_code_size = fork.max_code_size() - - code_prefix = Op.PUSH0 + Op.JUMPDEST - code_suffix = Op.PUSH1(1) + Op.JUMP - code_body_len = max_code_size - len(code_prefix) - len(code_suffix) - code_loop_iter = Op.CALLDATALOAD - code_body = code_loop_iter * (code_body_len // len(code_loop_iter)) - code = code_prefix + code_body + code_suffix - assert len(code) <= max_code_size - - tx = Transaction( - to=pre.deploy_contract(code=code), - data=calldata, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( + benchmark_test( pre=pre, post={}, - tx=tx, + code_generator=JumpLoopGenerator(setup=Op.PUSH0, attack_block=Op.CALLDATALOAD), ) @@ -2898,36 +2627,24 @@ def test_worst_swap( ], ) def test_worst_dup( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, opcode: Op, - gas_benchmark_value: int, -) -> None: +): """Test running a block with as many DUP as possible.""" max_stack_height = fork.max_stack_height() min_stack_height = opcode.min_stack_height - code_prefix = Op.PUSH0 * min_stack_height - opcode_sequence = opcode * (max_stack_height - min_stack_height) - target_contract_address = pre.deploy_contract(code=code_prefix + opcode_sequence) + code = Op.PUSH0 * min_stack_height + opcode * (max_stack_height - min_stack_height) + target_contract_address = pre.deploy_contract(code=code) - 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( - to=code_address, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( + benchmark_test( pre=pre, post={}, - tx=tx, + code_generator=JumpLoopGenerator(setup=Bytecode(), attack_block=attack_block), ) @@ -2970,40 +2687,17 @@ def test_worst_dup( ], ) def test_worst_push( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, - fork: Fork, opcode: Op, - gas_benchmark_value: int, -) -> None: +): """Test running a block with as many PUSH as possible.""" - op = opcode[1] if opcode.has_data_portion() else opcode - - 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( - to=code_address, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( + benchmark_test( pre=pre, post={}, - tx=tx, + code_generator=ExtCallGenerator( + setup=Bytecode(), attack_block=opcode[1] if opcode.has_data_portion() else opcode + ), ) @@ -3022,7 +2716,7 @@ def test_worst_push( ], ) def test_worst_return_revert( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, opcode: Op, @@ -3051,72 +2745,38 @@ def test_worst_return_revert( code += Op.INVALID * (max_code_size - len(executable_code)) target_contract_address = pre.deploy_contract(code=code) - calldata = Bytecode() attack_block = Op.POP(Op.STATICCALL(address=target_contract_address)) - code = code_loop_precompile_call(calldata, attack_block, fork) - code_address = pre.deploy_contract(code=code) - - tx = Transaction( - to=code_address, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - state_test( + benchmark_test( pre=pre, post={}, - tx=tx, + code_generator=JumpLoopGenerator(setup=Bytecode(), attack_block=attack_block), ) @pytest.mark.valid_from("Osaka") def test_worst_clz_same_input( - blockchain_test: BlockchainTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, gas_benchmark_value: int, env: Environment, ) -> None: """Test running a block with as many CLZ with same input as possible.""" - tx_gas_limit = fork.transaction_gas_limit_cap() or env.gas_limit - magic_value = 248 # CLZ(248) = 248 - calldata = Op.PUSH1(magic_value) - attack_block = Op.CLZ - code = code_loop_precompile_call(calldata, attack_block, fork) - assert len(code) <= fork.max_code_size() - - code_address = pre.deploy_contract(code=code) - - sender = pre.fund_eoa() - tx_count = gas_benchmark_value // tx_gas_limit - remainder_gas = gas_benchmark_value % tx_gas_limit - - txs = [ - Transaction( - to=code_address, - gas_limit=tx_gas_limit if i < tx_count else remainder_gas, - nonce=i, - sender=sender, - ) - for i in range(tx_count + 1) - ] - - blockchain_test( - genesis_environment=env, + benchmark_test( pre=pre, post={}, - blocks=[Block(txs=txs)], + code_generator=JumpLoopGenerator(setup=Op.PUSH1(magic_value), attack_block=Op.CLZ), ) @pytest.mark.valid_from("Osaka") def test_worst_clz_diff_input( - blockchain_test: BlockchainTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, - gas_benchmark_value: int, env: Environment, ) -> None: """ @@ -3142,24 +2802,13 @@ def test_worst_clz_diff_input( attack_code = code_prefix + code_seq + code_suffix assert len(attack_code) <= max_code_size - code_address = pre.deploy_contract(code=attack_code) - - sender = pre.fund_eoa() - tx_count = gas_benchmark_value // tx_gas_limit - remainder_gas = gas_benchmark_value % tx_gas_limit - txs = [ - Transaction( - to=code_address, - gas_limit=tx_gas_limit if i < tx_count else remainder_gas, - nonce=i, - sender=sender, - ) - for i in range(tx_count + 1) - ] + tx = Transaction( + to=pre.deploy_contract(code=attack_code), + sender=pre.fund_eoa(), + ) - blockchain_test( - genesis_environment=env, + benchmark_test( pre=pre, post={}, - blocks=[Block(txs=txs)], + tx=tx, ) From dd43d26993661e7190acf232f36fb029e98e55b9 Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Thu, 25 Sep 2025 14:06:11 +0800 Subject: [PATCH 04/18] refactor(benchmark): update worst memory scenario --- tests/benchmark/test_worst_memory.py | 156 +++++++++++---------------- 1 file changed, 60 insertions(+), 96 deletions(-) diff --git a/tests/benchmark/test_worst_memory.py b/tests/benchmark/test_worst_memory.py index 551bcd1a77d..19da8842aac 100755 --- a/tests/benchmark/test_worst_memory.py +++ b/tests/benchmark/test_worst_memory.py @@ -2,20 +2,21 @@ Tests that benchmark EVMs in the worst-case memory opcodes. """ +from enum import auto + import pytest from ethereum_test_base_types.base_types import Bytes +from ethereum_test_benchmark.benchmark_code_generator import JumpLoopGenerator from ethereum_test_forks import Fork from ethereum_test_tools import ( Alloc, + BenchmarkTestFiller, Bytecode, - StateTestFiller, Transaction, ) from ethereum_test_vm import Opcodes as Op -from .helpers import code_loop_precompile_call - REFERENCE_SPEC_GIT_PATH = "TODO" REFERENCE_SPEC_VERSION = "TODO" @@ -23,8 +24,8 @@ class CallDataOrigin: """Enum for calldata origins.""" - TRANSACTION = 1 - CALL = 2 + TRANSACTION = auto() + CALL = auto() @pytest.mark.parametrize( @@ -58,7 +59,7 @@ class CallDataOrigin: ], ) def test_worst_calldatacopy( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, origin: CallDataOrigin, @@ -81,35 +82,38 @@ def test_worst_calldatacopy( if min_gas > gas_benchmark_value: pytest.skip("Minimum gas required for calldata ({min_gas}) is greater than the gas limit") - # We create the contract that will be doing the CALLDATACOPY multiple - # times. - # If `non_zero_data` is True, we leverage CALLDATASIZE for the copy length. - # Otherwise, since we don't send zero data explicitly via calldata, PUSH - # the target size and use DUP1 to copy it. - prefix = Bytecode() if non_zero_data or size == 0 else Op.PUSH3(size) + # We create the contract that will be doing the CALLDATACOPY multiple times. + # + # If `non_zero_data` is True, we leverage CALLDATASIZE for the copy length. Otherwise, since we + # don't send zero data explicitly via calldata, PUSH the target size and use DUP1 to copy it. + setup = Bytecode() if non_zero_data or size == 0 else Op.PUSH3(size) src_dst = 0 if fixed_src_dst else Op.MOD(Op.GAS, 7) attack_block = Op.CALLDATACOPY( src_dst, src_dst, Op.CALLDATASIZE if non_zero_data or size == 0 else Op.DUP1 ) - code = code_loop_precompile_call(prefix, attack_block, fork) - code_address = pre.deploy_contract(code=code) + + code_address = JumpLoopGenerator(setup=setup, attack_block=attack_block).deploy_contracts( + pre, fork + ) tx_target = code_address # If the origin is CALL, we need to create a contract that will call the # target contract with the calldata. if origin == CallDataOrigin.CALL: - # If `non_zero_data` is False we leverage just using zeroed memory. - # Otherwise, we copy the calldata received from the transaction. - prefix = ( + # If `non_zero_data` is False we leverage just using zeroed memory. Otherwise, we + # copy the calldata received from the transaction. + setup = ( Op.CALLDATACOPY(Op.PUSH0, Op.PUSH0, Op.CALLDATASIZE) if non_zero_data else Bytecode() ) + Op.JUMPDEST arg_size = Op.CALLDATASIZE if non_zero_data else size - code = prefix + Op.STATICCALL( + attack_block = Op.STATICCALL( address=code_address, args_offset=Op.PUSH0, args_size=arg_size ) - code += Op.JUMP(len(prefix) - 1) - tx_target = pre.deploy_contract(code=code) + + tx_target = JumpLoopGenerator(setup=setup, attack_block=attack_block).deploy_contracts( + pre, fork + ) tx = Transaction( to=tx_target, @@ -118,7 +122,7 @@ def test_worst_calldatacopy( sender=pre.fund_eoa(), ) - state_test( + benchmark_test( pre=pre, post={}, tx=tx, @@ -143,38 +147,39 @@ def test_worst_calldatacopy( ], ) def test_worst_codecopy( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, max_code_size_ratio: float, fixed_src_dst: bool, - gas_benchmark_value: int, -) -> None: +): """Test running a block filled with CODECOPY executions.""" max_code_size = fork.max_code_size() size = int(max_code_size * max_code_size_ratio) - code_prefix = Op.PUSH32(size) + setup = Op.PUSH32(size) src_dst = 0 if fixed_src_dst else Op.MOD(Op.GAS, 7) attack_block = Op.CODECOPY(src_dst, src_dst, Op.DUP1) # DUP1 copies size. - code = code_loop_precompile_call(code_prefix, attack_block, fork) - # The code generated above is not guaranteed to be of max_code_size, so we - # pad it since a test parameter targets CODECOPYing a contract with max - # code size. Padded bytecode values are not relevant. - code = code + Op.INVALID * (max_code_size - len(code)) + code = JumpLoopGenerator(setup=setup, attack_block=attack_block).generate_repeated_code( + attack_block, Bytecode(), Bytecode(), fork + ) + + # The code generated above is not guaranteed to be of max_code_size, so we pad it since + # a test parameter targets CODECOPYing a contract with max code size. Padded bytecode values + # are not relevant. + code += Op.INVALID * (max_code_size - len(code)) assert len(code) == max_code_size, ( f"Code size {len(code)} is not equal to max code size {max_code_size}." ) tx = Transaction( to=pre.deploy_contract(code=code), - gas_limit=gas_benchmark_value, sender=pre.fund_eoa(), ) - state_test( + benchmark_test( pre=pre, post={}, tx=tx, @@ -198,20 +203,15 @@ def test_worst_codecopy( ], ) def test_worst_returndatacopy( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, - fork: Fork, size: int, fixed_dst: bool, - gas_benchmark_value: int, -) -> None: +): """Test running a block filled with RETURNDATACOPY executions.""" - max_code_size = fork.max_code_size() - - # Create the contract that will RETURN the data that will be used for - # RETURNDATACOPY. Random-ish data is injected at different points in memory - # to avoid making the content predictable. If `size` is 0, this helper - # contract won't be used. + # Create the contract that will RETURN the data that will be used for RETURNDATACOPY. + # Random-ish data is injected at different points in memory to avoid making the content + # predictable. If `size` is 0, this helper contract won't be used. code = ( Op.MSTORE8(0, Op.GAS) + Op.MSTORE8(size // 2, Op.GAS) @@ -220,14 +220,13 @@ def test_worst_returndatacopy( ) helper_contract = pre.deploy_contract(code=code) - # We create the contract that will be doing the RETURNDATACOPY multiple - # times. returndata_gen = Op.STATICCALL(address=helper_contract) if size > 0 else Bytecode() dst = 0 if fixed_dst else Op.MOD(Op.GAS, 7) - attack_iter = Op.RETURNDATACOPY(dst, Op.PUSH0, Op.RETURNDATASIZE) - jumpdest = Op.JUMPDEST - jump_back = Op.JUMP(len(returndata_gen)) + # We create the contract that will be doing the RETURNDATACOPY multiple times. + returndata_gen = Op.STATICCALL(address=helper_contract) if size > 0 else Bytecode() + attack_block = Op.RETURNDATACOPY(dst, Op.PUSH0, Op.RETURNDATASIZE) + # The attack loop is constructed as: # ``` # JUMPDEST(#) @@ -237,32 +236,15 @@ def test_worst_returndatacopy( # STATICCALL(address=helper_contract) # JUMP(#) # ``` - # The goal is that once per (big) loop iteration, the helper contract is - # called to generate fresh returndata to continue calling RETURNDATACOPY. - max_iters_loop = ( - max_code_size - 2 * len(returndata_gen) - len(jumpdest) - len(jump_back) - ) // len(attack_iter) - code = ( - returndata_gen - + jumpdest - + sum([attack_iter] * max_iters_loop) - + returndata_gen - + jump_back - ) - assert len(code) <= max_code_size, ( - f"Code size {len(code)} is not equal to max code size {max_code_size}." - ) + # The goal is that once per (big) loop iteration, the helper contract is called to + # generate fresh returndata to continue calling RETURNDATACOPY. - tx = Transaction( - to=pre.deploy_contract(code=code), - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( + benchmark_test( pre=pre, post={}, - tx=tx, + code_generator=JumpLoopGenerator( + setup=returndata_gen, attack_block=attack_block, cleanup=returndata_gen + ), ) @@ -283,42 +265,24 @@ def test_worst_returndatacopy( ], ) def test_worst_mcopy( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, - fork: Fork, size: int, fixed_src_dst: bool, - gas_benchmark_value: int, -) -> None: +): """Test running a block filled with MCOPY executions.""" - max_code_size = fork.max_code_size() + src_dst = 0 if fixed_src_dst else Op.MOD(Op.GAS, 7) + attack_block = Op.MCOPY(src_dst, src_dst, size) mem_touch = ( Op.MSTORE8(0, Op.GAS) + Op.MSTORE8(size // 2, Op.GAS) + Op.MSTORE8(size - 1, Op.GAS) if size > 0 else Bytecode() ) - src_dst = 0 if fixed_src_dst else Op.MOD(Op.GAS, 7) - attack_block = Op.MCOPY(src_dst, src_dst, size) - - jumpdest = Op.JUMPDEST - jump_back = Op.JUMP(len(mem_touch)) - max_iters_loop = (max_code_size - 2 * len(mem_touch) - len(jumpdest) - len(jump_back)) // len( - attack_block - ) - code = mem_touch + jumpdest + sum([attack_block] * max_iters_loop) + mem_touch + jump_back - assert len(code) <= max_code_size, ( - f"Code size {len(code)} is not equal to max code size {max_code_size}." - ) - - tx = Transaction( - to=pre.deploy_contract(code=code), - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( + benchmark_test( pre=pre, post={}, - tx=tx, + code_generator=JumpLoopGenerator( + setup=mem_touch, attack_block=attack_block, cleanup=mem_touch + ), ) From b02abd302642c881207ea16d90c6e855372c1c7a Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Thu, 25 Sep 2025 14:06:21 +0800 Subject: [PATCH 05/18] refactor(benchmark): update worst opcode scenario --- tests/benchmark/test_worst_opcode.py | 40 ++++++++-------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/tests/benchmark/test_worst_opcode.py b/tests/benchmark/test_worst_opcode.py index 4a220875c36..82479d4c9ec 100755 --- a/tests/benchmark/test_worst_opcode.py +++ b/tests/benchmark/test_worst_opcode.py @@ -4,18 +4,15 @@ import pytest -from ethereum_test_forks import Fork +from ethereum_test_benchmark.benchmark_code_generator import JumpLoopGenerator from ethereum_test_tools import ( Alloc, + BenchmarkTestFiller, Bytecode, - StateTestFiller, - Transaction, ) from ethereum_test_vm import Opcode from ethereum_test_vm import Opcodes as Op -from .helpers import code_loop_precompile_call - @pytest.mark.parametrize( "opcode", @@ -40,30 +37,26 @@ ) @pytest.mark.parametrize("fixed_offset", [True, False]) def test_worst_log_opcodes( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, - fork: Fork, opcode: Opcode, zeros_topic: bool, size: int, fixed_offset: bool, non_zero_data: bool, - gas_benchmark_value: int, -) -> None: +): """Test running a block with as many LOG opcodes as possible.""" - max_code_size = fork.max_code_size() - - calldata = Bytecode() + setup = Bytecode() # For non-zero data, load into memory. if non_zero_data: - calldata += Op.CODECOPY(dest_offset=0, offset=0, size=Op.CODESIZE) + setup += Op.CODECOPY(dest_offset=0, offset=0, size=Op.CODESIZE) # Push the size value onto the stack and access it using the DUP opcode. - calldata += Op.PUSH3(size) + setup += Op.PUSH3(size) # For non-zeros topic, push a non-zero value for topic. - calldata += Op.PUSH0 if zeros_topic else Op.PUSH32(2**256 - 1) + setup += Op.PUSH0 if zeros_topic else Op.PUSH32(2**256 - 1) topic_count = len(opcode.kwargs or []) - 2 offset = Op.PUSH0 if fixed_offset else Op.MOD(Op.GAS, 7) @@ -72,21 +65,10 @@ def test_worst_log_opcodes( # 0 topics -> DUP1, 1 topic -> DUP2, N topics -> DUP(N+1) size_op = getattr(Op, f"DUP{topic_count + 2}") - code_sequence = Op.DUP1 * topic_count + size_op + offset + opcode - - code = code_loop_precompile_call(calldata, code_sequence, fork) - assert len(code) <= max_code_size - - code_address = pre.deploy_contract(code=code) - - tx = Transaction( - to=code_address, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) + attack_block = Op.DUP1 * topic_count + size_op + offset + opcode - state_test( + benchmark_test( pre=pre, post={}, - tx=tx, + code_generator=JumpLoopGenerator(setup=setup, attack_block=attack_block), ) From 11028d6c458ddc7b960c01ed3222c2f13150b15a Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Thu, 25 Sep 2025 14:06:31 +0800 Subject: [PATCH 06/18] refactor(benchmark): update worst statefule scenario --- .../benchmark/test_worst_stateful_opcodes.py | 131 +++++------------- 1 file changed, 38 insertions(+), 93 deletions(-) diff --git a/tests/benchmark/test_worst_stateful_opcodes.py b/tests/benchmark/test_worst_stateful_opcodes.py index 95162625102..bcdd2bbdc45 100755 --- a/tests/benchmark/test_worst_stateful_opcodes.py +++ b/tests/benchmark/test_worst_stateful_opcodes.py @@ -3,20 +3,22 @@ """ import math +from enum import auto import pytest +from ethereum_test_benchmark.benchmark_code_generator import ExtCallGenerator, JumpLoopGenerator from ethereum_test_forks import Fork +from ethereum_test_specs import BlockchainTestFiller, StateTestFiller +from ethereum_test_specs.benchmark import BenchmarkTestFiller from ethereum_test_tools import ( Account, Address, Alloc, Block, - BlockchainTestFiller, Bytecode, Environment, Hash, - StateTestFiller, Transaction, While, compute_create2_address, @@ -24,8 +26,6 @@ ) from ethereum_test_vm import Opcodes as Op -from .helpers import code_loop_precompile_call - REFERENCE_SPEC_GIT_PATH = "TODO" REFERENCE_SPEC_VERSION = "TODO" @@ -44,7 +44,7 @@ ], ) def test_worst_address_state_cold( - blockchain_test: BlockchainTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, opcode: Op, @@ -107,11 +107,10 @@ def test_worst_address_state_cold( ) blocks.append(Block(txs=[op_tx])) - blockchain_test( + benchmark_test( pre=pre, post=post, blocks=blocks, - exclude_full_post_state_in_output=True, ) @@ -135,20 +134,12 @@ def test_worst_address_state_cold( ], ) def test_worst_address_state_warm( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, - fork: Fork, opcode: Op, absent_target: bool, - gas_benchmark_value: int, -) -> None: - """ - Test running a block with as many stateful opcodes doing warm access for an - account. - """ - max_code_size = fork.max_code_size() - attack_gas_limit = gas_benchmark_value - +): + """Test running a block with as many stateful opcodes doing warm access for an account.""" # Setup target_addr = Address(100_000) post = {} @@ -158,45 +149,29 @@ def test_worst_address_state_warm( post[target_addr] = Account(balance=100, code=code) # Execution - prep = Op.MSTORE(0, target_addr) - jumpdest = Op.JUMPDEST - jump_back = Op.JUMP(len(prep)) - iter_block = Op.POP(opcode(address=Op.MLOAD(0))) - max_iters_loop = (max_code_size - len(prep) - len(jumpdest) - len(jump_back)) // len( - iter_block - ) - op_code = prep + jumpdest + sum([iter_block] * max_iters_loop) + jump_back - if len(op_code) > max_code_size: - # Must never happen, but keep it as a sanity check. - raise ValueError(f"Code size {len(op_code)} exceeds maximum code size {max_code_size}") - op_address = pre.deploy_contract(code=op_code) - tx = Transaction( - to=op_address, - gas_limit=attack_gas_limit, - sender=pre.fund_eoa(), - ) - - state_test( + setup = Op.MSTORE(0, target_addr) + attack_block = Op.POP(opcode(address=Op.MLOAD(0))) + benchmark_test( pre=pre, post=post, - tx=tx, + code_generator=JumpLoopGenerator(setup=setup, attack_block=attack_block), ) class StorageAction: """Enum for storage actions.""" - READ = 1 - WRITE_SAME_VALUE = 2 - WRITE_NEW_VALUE = 3 + READ = auto() + WRITE_SAME_VALUE = auto() + WRITE_NEW_VALUE = auto() class TransactionResult: """Enum for the possible transaction outcomes.""" - SUCCESS = 1 - OUT_OF_GAS = 2 - REVERT = 3 + SUCCESS = auto() + OUT_OF_GAS = auto() + REVERT = auto() @pytest.mark.parametrize( @@ -247,7 +222,7 @@ class TransactionResult: ], ) def test_worst_storage_access_cold( - blockchain_test: BlockchainTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, storage_action: StorageAction, @@ -261,7 +236,6 @@ def test_worst_storage_access_cold( """ gas_costs = fork.gas_costs() intrinsic_gas_cost_calc = fork.transaction_intrinsic_cost_calculator() - attack_gas_limit = gas_benchmark_value loop_cost = gas_costs.G_COLD_SLOAD # All accesses are always cold if storage_action == StorageAction.WRITE_NEW_VALUE: @@ -311,7 +285,7 @@ def test_worst_storage_access_cold( ) num_target_slots = ( - attack_gas_limit - intrinsic_gas_cost_calc() - prefix_cost - suffix_cost + gas_benchmark_value - intrinsic_gas_cost_calc() - prefix_cost - suffix_cost ) // loop_cost if tx_result == TransactionResult.OUT_OF_GAS: # Add an extra slot to make it run out-of-gas @@ -369,18 +343,17 @@ def test_worst_storage_access_cold( op_tx = Transaction( to=contract_address, - gas_limit=attack_gas_limit, + gas_limit=gas_benchmark_value, sender=pre.fund_eoa(), ) blocks.append(Block(txs=[op_tx])) - blockchain_test( + benchmark_test( pre=pre, post={}, blocks=blocks, - exclude_full_post_state_in_output=True, expected_benchmark_gas_used=( - total_gas_used if tx_result != TransactionResult.OUT_OF_GAS else attack_gas_limit + total_gas_used if tx_result != TransactionResult.OUT_OF_GAS else gas_benchmark_value ), ) @@ -394,17 +367,13 @@ def test_worst_storage_access_cold( ], ) def test_worst_storage_access_warm( - blockchain_test: BlockchainTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, storage_action: StorageAction, - env: Environment, gas_benchmark_value: int, -) -> None: - """ - Test running a block with as many warm storage slot accesses as possible. - """ - attack_gas_limit = gas_benchmark_value - + env: Environment, +): + """Test running a block with as many warm storage slot accesses as possible.""" blocks = [] # The target storage slot for the warm access is storage slot 0. @@ -447,12 +416,12 @@ def test_worst_storage_access_warm( op_tx = Transaction( to=contract_address, - gas_limit=attack_gas_limit, + gas_limit=gas_benchmark_value, sender=pre.fund_eoa(), ) blocks.append(Block(txs=[op_tx])) - blockchain_test( + benchmark_test( pre=pre, post={}, blocks=blocks, @@ -491,35 +460,14 @@ def test_worst_blockhash( def test_worst_selfbalance( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, - fork: Fork, - gas_benchmark_value: int, -) -> None: +): """Test running a block with as many SELFBALANCE opcodes as possible.""" - max_stack_height = fork.max_stack_height() - - code_sequence = Op.SELFBALANCE * max_stack_height - target_address = pre.deploy_contract(code=code_sequence) - - calldata = Bytecode() - attack_block = Op.POP(Op.STATICCALL(Op.GAS, target_address, 0, 0, 0, 0)) - - code = code_loop_precompile_call(calldata, attack_block, fork) - assert len(code) <= fork.max_code_size() - - code_address = pre.deploy_contract(code=code) - - tx = Transaction( - to=code_address, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( + benchmark_test( pre=pre, post={}, - tx=tx, + code_generator=ExtCallGenerator(setup=Bytecode(), attack_block=Op.SELFBALANCE), ) @@ -532,7 +480,7 @@ def test_worst_selfbalance( ], ) def test_worst_extcodecopy_warm( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, copied_size: int, gas_benchmark_value: int, @@ -556,7 +504,7 @@ def test_worst_extcodecopy_warm( sender=pre.fund_eoa(), ) - state_test( + benchmark_test( pre=pre, post={}, tx=tx, @@ -565,7 +513,7 @@ def test_worst_extcodecopy_warm( @pytest.mark.parametrize("value_bearing", [True, False]) def test_worst_selfdestruct_existing( - blockchain_test: BlockchainTestFiller, + benchmark_test: BenchmarkTestFiller, fork: Fork, pre: Alloc, value_bearing: bool, @@ -696,14 +644,13 @@ def test_worst_selfdestruct_existing( post[deployed_contract_address] = Account(nonce=1) deployed_contract_addresses.append(deployed_contract_address) - blockchain_test( + benchmark_test( pre=pre, post=post, blocks=[ Block(txs=[contracts_deployment_tx]), Block(txs=[opcode_tx], fee_recipient=fee_recipient), ], - exclude_full_post_state_in_output=True, expected_benchmark_gas_used=expected_benchmark_gas_used, ) @@ -800,7 +747,6 @@ def test_worst_selfdestruct_created( post = {code_addr: Account(storage={0: 42})} # Check for successful # execution. state_test( - env=env, pre=pre, post=post, tx=code_tx, @@ -886,7 +832,6 @@ def test_worst_selfdestruct_initcode( post = {code_addr: Account(storage={0: 42})} # Check for successful # execution. state_test( - env=env, pre=pre, post=post, tx=code_tx, From 5dbf5e4f97646662fb89e582f25bd4a80eff5900 Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Thu, 25 Sep 2025 15:14:52 +0800 Subject: [PATCH 07/18] refactor(benchmark): update modexp cases by parameterization --- tests/benchmark/test_worst_compute.py | 1086 +++++++------------------ 1 file changed, 300 insertions(+), 786 deletions(-) diff --git a/tests/benchmark/test_worst_compute.py b/tests/benchmark/test_worst_compute.py index 2d62d90235e..c7be6c449c3 100755 --- a/tests/benchmark/test_worst_compute.py +++ b/tests/benchmark/test_worst_compute.py @@ -410,834 +410,348 @@ def test_worst_precompile_only_data_input( ) -@pytest.mark.parametrize( - ["mod_exp_input"], - [ - pytest.param( - ModExpInput( - base=8 * "ff", - exponent=112 * "ff", - modulus=7 * "ff" + "00", - ), - id="mod_even_8b_exp_896", - ), - pytest.param( - ModExpInput( - base=16 * "ff", - exponent=40 * "ff", - modulus=15 * "ff" + "00", - ), - id="mod_even_16b_exp_320", - ), - pytest.param( - ModExpInput( - base=24 * "ff", - exponent=21 * "ff", - modulus=23 * "ff" + "00", - ), - id="mod_even_24b_exp_168", - ), - pytest.param( - ModExpInput( - base=32 * "ff", - exponent=5 * "ff", - modulus=31 * "ff" + "00", - ), - id="mod_even_32b_exp_40", - ), - pytest.param( - ModExpInput( - base=32 * "ff", - exponent=12 * "ff", - modulus=31 * "ff" + "00", - ), - id="mod_even_32b_exp_96", - ), - pytest.param( - ModExpInput( - base=32 * "ff", - exponent=32 * "ff", - modulus=31 * "ff" + "00", - ), - id="mod_even_32b_exp_256", - ), - pytest.param( - ModExpInput( - base=64 * "ff", - exponent=64 * "ff", - modulus=63 * "ff" + "00", - ), - id="mod_even_64b_exp_512", - ), - pytest.param( - ModExpInput( - base=128 * "ff", - exponent=128 * "ff", - modulus=127 * "ff" + "00", - ), - id="mod_even_128b_exp_1024", - ), - pytest.param( - ModExpInput( - base=256 * "ff", - exponent=128 * "ff", - modulus=255 * "ff" + "00", - ), - id="mod_even_256b_exp_1024", - ), - pytest.param( - ModExpInput( - base=512 * "ff", - exponent=128 * "ff", - modulus=511 * "ff" + "00", - ), - id="mod_even_512b_exp_1024", - ), - pytest.param( - ModExpInput( - base=1024 * "ff", - exponent=128 * "ff", - modulus=1023 * "ff" + "00", - ), - id="mod_even_1024b_exp_1024", - ), - pytest.param( - ModExpInput( - base=32 * "ff", - exponent=12 * "ff", - modulus=31 * "ff" + "01", - ), - id="mod_odd_32b_exp_96", - ), - pytest.param( - ModExpInput( - base=32 * "ff", - exponent=32 * "ff", - modulus=31 * "ff" + "01", - ), - id="mod_odd_32b_exp_256", - ), - pytest.param( - ModExpInput( - base=64 * "ff", - exponent=64 * "ff", - modulus=63 * "ff" + "01", - ), - id="mod_odd_64b_exp_512", - ), - pytest.param( - ModExpInput( - base=128 * "ff", - exponent=128 * "ff", - modulus=127 * "ff" + "01", - ), - id="mod_odd_128b_exp_1024", - ), - pytest.param( - ModExpInput( - base=256 * "ff", - exponent=128 * "ff", - modulus=255 * "ff" + "01", - ), - id="mod_odd_256b_exp_1024", - ), - pytest.param( - ModExpInput( - base=512 * "ff", - exponent=128 * "ff", - modulus=511 * "ff" + "01", - ), - id="mod_odd_512b_exp_1024", - ), - pytest.param( - ModExpInput( - base=1024 * "ff", - exponent=128 * "ff", - modulus=1023 * "ff" + "01", - ), - id="mod_odd_1024b_exp_1024", - ), - pytest.param( - ModExpInput( - base=32 * "ff", - exponent=8 * "12345670", - modulus=31 * "ff" + "01", - ), - id="mod_odd_32b_exp_cover_windows", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L38 - pytest.param( - ModExpInput( - base=192 * "FF", - exponent="03", - modulus=6 * ("00" + 31 * "FF"), - ), - id="mod_min_gas_base_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L40 - pytest.param( - ModExpInput( - base=8 * "FF", - exponent="07" + 75 * "FF", - modulus=7 * "FF", - ), - id="mod_min_gas_exp_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L42 - pytest.param( - ModExpInput( - base=40 * "FF", - exponent="01" + 3 * "FF", - modulus="00" + 38 * "FF", - ), - id="mod_min_gas_balanced", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L44 - pytest.param( - ModExpInput( - base=32 * "FF", - exponent=5 * "FF", - modulus=("00" + 31 * "FF"), - ), - id="mod_exp_208_gas_balanced", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L46 - pytest.param( - ModExpInput( - base=8 * "FF", - exponent=81 * "FF", - modulus=7 * "FF", - ), - id="mod_exp_215_gas_exp_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L48 - pytest.param( - ModExpInput( - base=8 * "FF", - exponent=112 * "FF", - modulus=7 * "FF", - ), - id="mod_exp_298_gas_exp_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L50 - pytest.param( - ModExpInput( - base=16 * "FF", - exponent=40 * "FF", - modulus=15 * "FF", - ), - id="mod_pawel_2", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L52 - pytest.param( - ModExpInput( - base=24 * "FF", - exponent=21 * "FF", - modulus=23 * "FF", - ), - id="mod_pawel_3", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L54 - pytest.param( - ModExpInput( - base=32 * "FF", - exponent=12 * "FF", - modulus="00" + 31 * "FF", - ), - id="mod_pawel_4", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L56 - pytest.param( - ModExpInput( - base=280 * "FF", - exponent="03", - modulus=8 * ("00" + 31 * "FF") + 23 * "FF", - ), - id="mod_408_gas_base_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L58 - pytest.param( - ModExpInput( - base=16 * "FF", - exponent="15" + 37 * "FF", - modulus=15 * "FF", - ), - id="mod_400_gas_exp_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L60 - pytest.param( - ModExpInput( - base=48 * "FF", - exponent="07" + 4 * "FF", - modulus="00" + 46 * "FF", - ), - id="mod_408_gas_balanced", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L62 - pytest.param( - ModExpInput( - base=344 * "FF", - exponent="03", - modulus=10 * ("00" + 31 * "FF") + 23 * "FF", - ), - id="mod_616_gas_base_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L64 - pytest.param( - ModExpInput( - base=16 * "FF", - exponent="07" + 56 * "FF", - modulus=15 * "FF", - ), - id="mod_600_gas_exp_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L66 - pytest.param( - ModExpInput( - base=48 * "FF", - exponent="07" + 6 * "FF", - modulus="00" + 46 * "FF", - ), - id="mod_600_gas_balanced", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L68 - pytest.param( - ModExpInput( - base=392 * "FF", - exponent="03", - modulus=12 * ("00" + 31 * "FF") + 7 * "FF", - ), - id="mod_800_gas_base_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L70 - pytest.param( - ModExpInput( - base=16 * "FF", - exponent="01" + 75 * "FF", - modulus=15 * "FF", - ), - id="mod_800_gas_exp_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L72 - pytest.param( - ModExpInput( - base=56 * "FF", - exponent=6 * "FF", - modulus="00" + 54 * "FF", - ), - id="mod_767_gas_balanced", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L74 - pytest.param( - ModExpInput( - base=16 * "FF", - exponent=80 * "FF", - modulus=15 * "FF", - ), - id="mod_852_gas_exp_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L76 - pytest.param( - ModExpInput( - base=408 * "FF", - exponent="03", - modulus=12 * ("00" + 31 * "FF") + 23 * "FF", - ), - id="mod_867_gas_base_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L78 - pytest.param( - ModExpInput( - base=56 * "FF", - exponent="2b" + 7 * "FF", - modulus="00" + 54 * "FF", - ), - id="mod_996_gas_balanced", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L80 - pytest.param( - ModExpInput( - base=448 * "FF", - exponent="03", - modulus=14 * ("00" + 31 * "FF"), - ), - id="mod_1045_gas_base_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L82 - pytest.param( - ModExpInput( - base=32 * "FF", - exponent=16 * "FF", - modulus="00" + 31 * "FF", - ), - id="mod_677_gas_base_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L84 - pytest.param( - ModExpInput( - base=24 * "FF", - exponent=32 * "FF", - modulus=23 * "FF", - ), - id="mod_765_gas_exp_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L86 - pytest.param( - ModExpInput( - base=32 * "FF", - exponent=32 * "FF", - modulus="00" + 31 * "FF", - ), - id="mod_1360_gas_balanced", - ), - pytest.param( - ModExpInput( - base=8 * "FF", - exponent=81 * "FF", - modulus=7 * "FF", - ), - id="mod_8_exp_648", - ), - pytest.param( - ModExpInput( - base=8 * "FF", - exponent="FF" + 111 * "FF", - modulus=7 * "FF", - ), - id="mod_8_exp_896", - ), - pytest.param( - ModExpInput( - base=32 * "FF", - exponent=4 * "FF", - modulus="00" + 31 * "FF", - ), - id="mod_32_exp_32", +def create_modexp_test_cases(): + """Create test cases for the MODEXP precompile.""" + test_cases = [ + # (base, exponent, modulus, test_id) + (8 * "ff", 112 * "ff", 7 * "ff" + "00", "mod_even_8b_exp_896"), + (16 * "ff", 40 * "ff", 15 * "ff" + "00", "mod_even_16b_exp_320"), + (24 * "ff", 21 * "ff", 23 * "ff" + "00", "mod_even_24b_exp_168"), + (32 * "ff", 5 * "ff", 31 * "ff" + "00", "mod_even_32b_exp_40"), + (32 * "ff", 12 * "ff", 31 * "ff" + "00", "mod_even_32b_exp_96"), + (32 * "ff", 32 * "ff", 31 * "ff" + "00", "mod_even_32b_exp_256"), + (64 * "ff", 64 * "ff", 63 * "ff" + "00", "mod_even_64b_exp_512"), + (128 * "ff", 128 * "ff", 127 * "ff" + "00", "mod_even_128b_exp_1024"), + (256 * "ff", 128 * "ff", 255 * "ff" + "00", "mod_even_256b_exp_1024"), + (512 * "ff", 128 * "ff", 511 * "ff" + "00", "mod_even_512b_exp_1024"), + (1024 * "ff", 128 * "ff", 1023 * "ff" + "00", "mod_even_1024b_exp_1024"), + (32 * "ff", 12 * "ff", 31 * "ff" + "01", "mod_odd_32b_exp_96"), + (32 * "ff", 32 * "ff", 31 * "ff" + "01", "mod_odd_32b_exp_256"), + (64 * "ff", 64 * "ff", 63 * "ff" + "01", "mod_odd_64b_exp_512"), + (128 * "ff", 128 * "ff", 127 * "ff" + "01", "mod_odd_128b_exp_1024"), + (256 * "ff", 128 * "ff", 255 * "ff" + "01", "mod_odd_256b_exp_1024"), + (512 * "ff", 128 * "ff", 511 * "ff" + "01", "mod_odd_512b_exp_1024"), + (1024 * "ff", 128 * "ff", 1023 * "ff" + "01", "mod_odd_1024b_exp_1024"), + (32 * "ff", 8 * "12345670", 31 * "ff" + "01", "mod_odd_32b_exp_cover_windows"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L38 + (192 * "FF", "03", 6 * ("00" + 31 * "FF"), "mod_min_gas_base_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L40 + (8 * "FF", "07" + 75 * "FF", 7 * "FF", "mod_min_gas_exp_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L42 + (40 * "FF", "01" + 3 * "FF", "00" + 38 * "FF", "mod_min_gas_balanced"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L44 + (32 * "FF", 5 * "FF", ("00" + 31 * "FF"), "mod_exp_208_gas_balanced"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L46 + (8 * "FF", 81 * "FF", 7 * "FF", "mod_exp_215_gas_exp_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L48 + (8 * "FF", 112 * "FF", 7 * "FF", "mod_exp_298_gas_exp_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L50 + (16 * "FF", 40 * "FF", 15 * "FF", "mod_pawel_2"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L52 + (24 * "FF", 21 * "FF", 23 * "FF", "mod_pawel_3"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L54 + (32 * "FF", 12 * "FF", "00" + 31 * "FF", "mod_pawel_4"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L56 + (280 * "FF", "03", 8 * ("00" + 31 * "FF") + 23 * "FF", "mod_408_gas_base_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L58 + (16 * "FF", "15" + 37 * "FF", 15 * "FF", "mod_400_gas_exp_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L60 + (48 * "FF", "07" + 4 * "FF", "00" + 46 * "FF", "mod_408_gas_balanced"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L62 + (344 * "FF", "03", 10 * ("00" + 31 * "FF") + 23 * "FF", "mod_616_gas_base_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L64 + (16 * "FF", "07" + 56 * "FF", 15 * "FF", "mod_600_gas_exp_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L66 + (48 * "FF", "07" + 6 * "FF", "00" + 46 * "FF", "mod_600_gas_balanced"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L68 + (392 * "FF", "03", 12 * ("00" + 31 * "FF") + 7 * "FF", "mod_800_gas_base_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L70 + (16 * "FF", "01" + 75 * "FF", 15 * "FF", "mod_800_gas_exp_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L72 + (56 * "FF", 6 * "FF", "00" + 54 * "FF", "mod_767_gas_balanced"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L74 + (16 * "FF", 80 * "FF", 15 * "FF", "mod_852_gas_exp_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L76 + (408 * "FF", "03", 12 * ("00" + 31 * "FF") + 23 * "FF", "mod_867_gas_base_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L78 + (56 * "FF", "2b" + 7 * "FF", "00" + 54 * "FF", "mod_996_gas_balanced"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L80 + (448 * "FF", "03", 14 * ("00" + 31 * "FF"), "mod_1045_gas_base_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L82 + (32 * "FF", 16 * "FF", "00" + 31 * "FF", "mod_677_gas_base_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L84 + (24 * "FF", 32 * "FF", 23 * "FF", "mod_765_gas_exp_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L86 + (32 * "FF", 32 * "FF", "00" + 31 * "FF", "mod_1360_gas_balanced"), + (8 * "FF", 81 * "FF", 7 * "FF", "mod_8_exp_648"), + (8 * "FF", "FF" + 111 * "FF", 7 * "FF", "mod_8_exp_896"), + (32 * "FF", 4 * "FF", "00" + 31 * "FF", "mod_32_exp_32"), + (32 * "FF", "0D" + 4 * "FF", "00" + 31 * "FF", "mod_32_exp_36"), + (32 * "FF", 5 * "FF", "00" + 31 * "FF", "mod_32_exp_40"), + (32 * "FF", 8 * "FF", "00" + 31 * "FF", "mod_32_exp_64"), + (32 * "FF", "01" + 8 * "FF", "00" + 31 * "FF", "mod_32_exp_65"), + (32 * "FF", 16 * "FF", "00" + 31 * "FF", "mod_32_exp_128"), + (256 * "FF", "03" + 0 * "FF", 8 * ("00" + 31 * "FF"), "mod_256_exp_2"), + (264 * "FF", "03" + 0 * "FF", 8 * ("00" + 31 * "FF") + 7 * "FF", "mod_264_exp_2"), + (1024 * "FF", "03", 32 * ("00" + 31 * "FF"), "mod_1024_exp_2"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L122 + ( + "03", + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "mod_vul_example_1", ), - pytest.param( - ModExpInput( - base=32 * "FF", - exponent="0D" + 4 * "FF", - modulus="00" + 31 * "FF", - ), - id="mod_32_exp_36", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L124 + ( + "", + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "mod_vul_example_2", ), - pytest.param( - ModExpInput( - base=32 * "FF", - exponent=5 * "FF", - modulus="00" + 31 * "FF", - ), - id="mod_32_exp_40", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L126 + ( + "e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5", + "02", + "fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b", + "mod_vul_nagydani_1_square", ), - pytest.param( - ModExpInput( - base=32 * "FF", - exponent=8 * "FF", - modulus="00" + 31 * "FF", - ), - id="mod_32_exp_64", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L128 + ( + "e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5", + "03", + "fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b", + "mod_vul_nagydani_1_qube", ), - pytest.param( - ModExpInput( - base=32 * "FF", - exponent="01" + 8 * "FF", - modulus="00" + 31 * "FF", - ), - id="mod_32_exp_65", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L130 + ( + "e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5", + "010001", + "fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b", + "mod_vul_nagydani_1_pow_0x10001", ), - pytest.param( - ModExpInput( - base=32 * "FF", - exponent=16 * "FF", - modulus="00" + 31 * "FF", - ), - id="mod_32_exp_128", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L132 + ( + "cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51", + "02", + "e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087", + "mod_vul_nagydani_2_square", ), - pytest.param( - ModExpInput( - base=256 * "FF", - exponent="03" + 0 * "FF", - modulus=8 * ("00" + 31 * "FF"), - ), - id="mod_256_exp_2", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L134 + ( + "cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51", + "03", + "e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087", + "mod_vul_nagydani_2_qube", ), - pytest.param( - ModExpInput( - base=264 * "FF", - exponent="03" + 0 * "FF", - modulus=8 * ("00" + 31 * "FF") + 7 * "FF", - ), - id="mod_264_exp_2", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L136 + ( + "cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51", + "010001", + "e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087", + "mod_vul_nagydani_2_pow_0x10001", ), - pytest.param( - ModExpInput( - base=1024 * "FF", - exponent="03", - modulus=32 * ("00" + 31 * "FF"), - ), - id="mod_1024_exp_2", + ( + "c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb", + "02", + "d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d", + "mod_vul_nagydani_3_square", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L122 - pytest.param( - ModExpInput( - base="03", - exponent="fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", - modulus="fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", - ), - id="mod_vul_example_1", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L140 + ( + "c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb", + "03", + "d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d", + "mod_vul_nagydani_3_qube", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L124 - pytest.param( - ModExpInput( - base="", - exponent="fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", - modulus="fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", - ), - id="mod_vul_example_2", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L142 + ( + "c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb", + "010001", + "d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d", + "mod_vul_nagydani_3_pow_0x10001", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L126 - pytest.param( - ModExpInput( - base="e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5", - exponent="02", - modulus="fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b", - ), - id="mod_vul_nagydani_1_square", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L144 + ( + "db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81", + "02", + "df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f", + "mod_vul_nagydani_4_square", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L128 - pytest.param( - ModExpInput( - base="e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5", - exponent="03", - modulus="fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b", - ), - id="mod_vul_nagydani_1_qube", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L146 + ( + "db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81", + "03", + "df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f", + "mod_vul_nagydani_4_qube", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L130 - pytest.param( - ModExpInput( - base="e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5", - exponent="010001", - modulus="fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b", - ), - id="mod_vul_nagydani_1_pow_0x10001", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L148 + ( + "db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81", + "010001", + "df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f", + "mod_vul_nagydani_4_pow_0x10001", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L132 - pytest.param( - ModExpInput( - base="cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51", - exponent="02", - modulus="e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087", - ), - id="mod_vul_nagydani_2_square", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L150 + ( + "c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf", + "02", + "e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad", + "mod_vul_nagydani_5_square", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L134 - pytest.param( - ModExpInput( - base="cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51", - exponent="03", - modulus="e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087", - ), - id="mod_vul_nagydani_2_qube", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L152 + ( + "c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf", + "03", + "e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad", + "mod_vul_nagydani_5_qube", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L136 - pytest.param( - ModExpInput( - base="cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51", - exponent="010001", - modulus="e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087", - ), - id="mod_vul_nagydani_2_pow_0x10001", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L154 + ( + "c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf", + "010001", + "e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad", + "mod_vul_nagydani_5_pow_0x10001", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L138 - pytest.param( - ModExpInput( - base="c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb", - exponent="02", - modulus="d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d", - ), - id="mod_vul_nagydani_3_square", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L156 + ( + "ffffff", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffe000007d7d7d83828282348286877d7d827d407d797d7d7d7d7d7d7d7d7d7d7d5b00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000021000000000000000000000000000000000000000000000000000000000000000cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4000007d7d", + "7d83828282348286877d7d82", + "mod_vul_marius_1_even", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L140 - pytest.param( - ModExpInput( - base="c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb", - exponent="03", - modulus="d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d", - ), - id="mod_vul_nagydani_3_qube", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L158 + ( + "ffffffffffffffff76ffffffffffffff", + "1cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c76ec7c7c7c7ffffffffffffffc7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7ffffffffffffc7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c76ec7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7ffff", + "ffffff3f000000000000000000000000", + "mod_vul_guido_1_even", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L142 - pytest.param( - ModExpInput( - base="c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb", - exponent="010001", - modulus="d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d", - ), - id="mod_vul_nagydani_3_pow_0x10001", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L160 + ( + "e0060000a921212121212121ff000021", + "2b212121ffff1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f00feffff212121212121ffffffff1fe1e0e0e01e1f1f169f1f1f1f490afcefffffffffffffffff82828282828282828282828282828282828282828200ffff28ff2b212121ffff1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1fffffffffff0afceffffff7ffffffffff7c8282828282a1828282828282828282828282828200ffff28ff2b212121ffff1f1f1f1f1f1fd11f1f1f1f1f1f1f1f1f1f1fffffffffffffffff21212121212121fb2121212121ffff1f1f1f1f1f1f1f1fffaf", + "82828282828200ffff28ff2b21828200", + "mod_vul_guido_2_even", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L144 - pytest.param( - ModExpInput( - base="db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81", - exponent="02", - modulus="df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f", - ), - id="mod_vul_nagydani_4_square", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L162 + ( + "0193585a48e18aad777e9c1b54221a0f58140392e4f091cd5f42b2e8644a9384fbd58ae1edec2477ebf7edbf7c0a3f8bd21d1890ee87646feab3c47be716f842cc3da9b940af312dc54450a960e3fc0b86e56abddd154068e10571a96fff6259431632bc15695c6c8679057e66c2c25c127e97e64ee5de6ea1fc0a4a0e431343fed1daafa072c238a45841da86a9806680bc9f298411173210790359209cd454b5af7b4d5688b4403924e5f863d97e2c5349e1a04b54fcf385b1e9d7714bab8fbf5835f6ff9ed575e77dff7af5cbb641db5d537933bae1fa6555d6c12d6fb31ca27b57771f4aebfbe0bf95e8990c0108ffe7cbdaf370be52cf3ade594543af75ad9329d2d11a402270b5b9a6bf4b83307506e118fca4862749d04e916fc7a039f0d13f2a02e0eedb800199ec95df15b4ccd8669b52586879624d51219e72102fad810b5909b1e372ddf33888fb9beb09b416e4164966edbabd89e4a286be36277fc576ed519a15643dac602e92b63d0b9121f0491da5b16ef793a967f096d80b6c81ecaaffad7e3f06a4a5ac2796f1ed9f68e6a0fd5cf191f0c5c2eec338952ff8d31abc68bf760febeb57e088995ba1d7726a2fdd6d8ca28a181378b8b4ab699bfd4b696739bbf17a9eb2df6251143046137fdbbfacac312ebf67a67da9741b59600000000000", + "04", + "19a2917c61722b0713d3b00a2f0e1dd5aebbbe09615de424700eea3c3020fe6e9ea5de9fa1ace781df28b21f746d2ab61d0da496e08473c90ff7dfe25b43bcde76f4bafb82e0975bea75f5a0591dba80ba2fff80a07d8853bea5be13ab326ba70c57b153acc646151948d1cf061ca31b02d4719fac710e7c723ca44f5b1737824b7ccc74ba5bff980aabdbf267621cafc3d6dcc29d0ca9c16839a92ed34de136da7900aa3ee43d21aa57498981124357cf0ca9b86f9a8d3f9c604ca00c726e48f7a9945021ea6dfff92d6b2d6514693169ca133e993541bfa4c4c191de806aa80c48109bcfc9901eccfdeb2395ab75fe63c67de900829d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "mod_vul_guido_3_even", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L146 - pytest.param( - ModExpInput( - base="db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81", - exponent="03", - modulus="df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f", - ), - id="mod_vul_nagydani_4_qube", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L166 + ( + "ffffffffffffffff", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "ffffffffffffffff", + "mod_vul_pawel_1_exp_heavy", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L148 - pytest.param( - ModExpInput( - base="db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81", - exponent="010001", - modulus="df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f", - ), - id="mod_vul_nagydani_4_pow_0x10001", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L168 + ( + "ffffffffffffffffffffffffffffffff", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "ffffffffffffffffffffffffffffffff", + "mod_vul_pawel_2_exp_heavy", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L150 - pytest.param( - ModExpInput( - base="c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf", - exponent="02", - modulus="e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad", - ), - id="mod_vul_nagydani_5_square", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L170 + ( + "ffffffffffffffffffffffffffffffffffffffffffffffff", + "ffffffffffffffffffffffffffffffffffffffffff", + "ffffffffffffffffffffffffffffffffffffffffffffffff", + "mod_vul_pawel_3_exp_heavy", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L152 - pytest.param( - ModExpInput( - base="c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf", - exponent="03", - modulus="e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad", - ), - id="mod_vul_nagydani_5_qube", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L172 + ( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "ffffffffffffffffffffffff", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "mod_vul_pawel_4_exp_heavy", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L154 - pytest.param( - ModExpInput( - base="c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf", - exponent="010001", - modulus="e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad", - ), - id="mod_vul_nagydani_5_pow_0x10001", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L174 + ( + "29356abadad68ad986c416de6f620bda0e1818b589e84f853a97391694d35496", + "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254f", + "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", + "mod_vul_common_1360n1", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L156 - pytest.param( - ModExpInput( - base="ffffff", - exponent="ffffffffffffffffffffffffffffffffffffffffffffffffffffffffe000007d7d7d83828282348286877d7d827d407d797d7d7d7d7d7d7d7d7d7d7d5b00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000021000000000000000000000000000000000000000000000000000000000000000cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4000007d7d", - modulus="7d83828282348286877d7d82", - ), - id="mod_vul_marius_1_even", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L176 + ( + "d41afaeaea32f7409827761b68c41b6e535da4ede1f0800bfb4a6aed18394f6b", + "ffffffff00000001000000000000000000000000fffffffffffffffffffffffd", + "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", + "mod_vul_common_1360n2", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L158 - pytest.param( - ModExpInput( - base="ffffffffffffffff76ffffffffffffff", - exponent="1cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c76ec7c7c7c7ffffffffffffffc7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7ffffffffffffc7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c76ec7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7ffff", - modulus="ffffff3f000000000000000000000000", - ), - id="mod_vul_guido_1_even", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L178 + ( + "1a5be8fae3b3fda9ea329494ae8689c04fae4978ecccfa6a6bfb9f04b25846c0", + "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff", + "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", + "mod_vul_common_1349n1", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L160 - pytest.param( - ModExpInput( - base="e0060000a921212121212121ff000021", - exponent="2b212121ffff1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f00feffff212121212121ffffffff1fe1e0e0e01e1f1f169f1f1f1f490afcefffffffffffffffff82828282828282828282828282828282828282828200ffff28ff2b212121ffff1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1fffffffffff0afceffffff7ffffffffff7c8282828282a1828282828282828282828282828200ffff28ff2b212121ffff1f1f1f1f1f1fd11f1f1f1f1f1f1f1f1f1f1fffffffffffffffff21212121212121fb2121212121ffff1f1f1f1f1f1f1f1fffaf", - modulus="82828282828200ffff28ff2b21828200", - ), - id="mod_vul_guido_2_even", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L182 + ( + "0000000000000000000000000000000000000000000000000000000000000003", + "0000000001000000000000022000000000000000000000000000000000000000", + "0800000000000011000000000000000000000000000000000000000000000001", + "mod_vul_common_1152n1", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L162 - pytest.param( - ModExpInput( - base="0193585a48e18aad777e9c1b54221a0f58140392e4f091cd5f42b2e8644a9384fbd58ae1edec2477ebf7edbf7c0a3f8bd21d1890ee87646feab3c47be716f842cc3da9b940af312dc54450a960e3fc0b86e56abddd154068e10571a96fff6259431632bc15695c6c8679057e66c2c25c127e97e64ee5de6ea1fc0a4a0e431343fed1daafa072c238a45841da86a9806680bc9f298411173210790359209cd454b5af7b4d5688b4403924e5f863d97e2c5349e1a04b54fcf385b1e9d7714bab8fbf5835f6ff9ed575e77dff7af5cbb641db5d537933bae1fa6555d6c12d6fb31ca27b57771f4aebfbe0bf95e8990c0108ffe7cbdaf370be52cf3ade594543af75ad9329d2d11a402270b5b9a6bf4b83307506e118fca4862749d04e916fc7a039f0d13f2a02e0eedb800199ec95df15b4ccd8669b52586879624d51219e72102fad810b5909b1e372ddf33888fb9beb09b416e4164966edbabd89e4a286be36277fc576ed519a15643dac602e92b63d0b9121f0491da5b16ef793a967f096d80b6c81ecaaffad7e3f06a4a5ac2796f1ed9f68e6a0fd5cf191f0c5c2eec338952ff8d31abc68bf760febeb57e088995ba1d7726a2fdd6d8ca28a181378b8b4ab699bfd4b696739bbf17a9eb2df6251143046137fdbbfacac312ebf67a67da9741b59600000000000", - exponent="04", - modulus="19a2917c61722b0713d3b00a2f0e1dd5aebbbe09615de424700eea3c3020fe6e9ea5de9fa1ace781df28b21f746d2ab61d0da496e08473c90ff7dfe25b43bcde76f4bafb82e0975bea75f5a0591dba80ba2fff80a07d8853bea5be13ab326ba70c57b153acc646151948d1cf061ca31b02d4719fac710e7c723ca44f5b1737824b7ccc74ba5bff980aabdbf267621cafc3d6dcc29d0ca9c16839a92ed34de136da7900aa3ee43d21aa57498981124357cf0ca9b86f9a8d3f9c604ca00c726e48f7a9945021ea6dfff92d6b2d6514693169ca133e993541bfa4c4c191de806aa80c48109bcfc9901eccfdeb2395ab75fe63c67de900829d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - ), - id="mod_vul_guido_3_even", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L184 + ( + "1fb473dd1171cf88116aa77ab3612c2c7d2cf466cc2386cc456130e2727c70b4", + "0000000000000000000000000000000000000000000000000000000001000000", + "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", + "mod_vul_common_200n1", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L166 - pytest.param( - ModExpInput( - base="ffffffffffffffff", - exponent="ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - modulus="ffffffffffffffff", - ), - id="mod_vul_pawel_1_exp_heavy", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L186 + ( + "1951441010b2b95a6e47a6075066a50a036f5ba978c050f2821df86636c0facb", + "0000000000000000000000000000000000000000000000000000000000ffffff", + "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", + "mod_vul_common_200n2", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L168 - pytest.param( - ModExpInput( - base="ffffffffffffffffffffffffffffffff", - exponent="ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - modulus="ffffffffffffffffffffffffffffffff", - ), - id="mod_vul_pawel_2_exp_heavy", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L188 + ( + "288254ba43e713afbe36c9f03b54c00fae4c0a82df1cf165eb46a21c20a48ca2", + "0000000000000000000000000000000000000000000000000000000000ffffff", + "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", + "mod_vul_common_200n3", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L170 - pytest.param( - ModExpInput( - base="ffffffffffffffffffffffffffffffffffffffffffffffff", - exponent="ffffffffffffffffffffffffffffffffffffffffff", - modulus="ffffffffffffffffffffffffffffffffffffffffffffffff", - ), - id="mod_vul_pawel_3_exp_heavy", + ( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", + "mod_vul_zkevm_worst_case", ), + ] + + special_cases = [ pytest.param( ModExpInput.from_bytes( "000000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000017bffffffffffffffffffffffffffffffffffffffffffffbffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffffffe" ), id="mod_vul_pawel_3_exp_8", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L172 - pytest.param( - ModExpInput( - base="ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - exponent="ffffffffffffffffffffffff", - modulus="ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ), - id="mod_vul_pawel_4_exp_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L174 - pytest.param( - ModExpInput( - base="29356abadad68ad986c416de6f620bda0e1818b589e84f853a97391694d35496", - exponent="ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254f", - modulus="ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", - ), - id="mod_vul_common_1360n1", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L176 - pytest.param( - ModExpInput( - base="d41afaeaea32f7409827761b68c41b6e535da4ede1f0800bfb4a6aed18394f6b", - exponent="ffffffff00000001000000000000000000000000fffffffffffffffffffffffd", - modulus="ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", - ), - id="mod_vul_common_1360n2", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L178 - pytest.param( - ModExpInput( - base="1a5be8fae3b3fda9ea329494ae8689c04fae4978ecccfa6a6bfb9f04b25846c0", - exponent="30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff", - modulus="30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", - ), - id="mod_vul_common_1349n1", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L182 - pytest.param( - ModExpInput( - base="0000000000000000000000000000000000000000000000000000000000000003", - exponent="0000000001000000000000022000000000000000000000000000000000000000", - modulus="0800000000000011000000000000000000000000000000000000000000000001", - ), - id="mod_vul_common_1152n1", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L184 - pytest.param( - ModExpInput( - base="1fb473dd1171cf88116aa77ab3612c2c7d2cf466cc2386cc456130e2727c70b4", - exponent="0000000000000000000000000000000000000000000000000000000001000000", - modulus="30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", - ), - id="mod_vul_common_200n1", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L186 - pytest.param( - ModExpInput( - base="1951441010b2b95a6e47a6075066a50a036f5ba978c050f2821df86636c0facb", - exponent="0000000000000000000000000000000000000000000000000000000000ffffff", - modulus="30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", - ), - id="mod_vul_common_200n2", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L188 - pytest.param( - ModExpInput( - base="288254ba43e713afbe36c9f03b54c00fae4c0a82df1cf165eb46a21c20a48ca2", - exponent="0000000000000000000000000000000000000000000000000000000000ffffff", - modulus="30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", - ), - id="mod_vul_common_200n3", - ), + ] + + regular_cases = [ pytest.param( ModExpInput( - base="ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - exponent="ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - modulus="fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", + base=base, + exponent=exponent, + modulus=modulus, ), - id="mod_vul_zkevm_worst_case", - ), - ], + id=test_id, + ) + for base, exponent, modulus, test_id in test_cases + ] + + return regular_cases + special_cases + + +@pytest.mark.parametrize( + ["mod_exp_input"], + create_modexp_test_cases(), ) def test_worst_modexp( benchmark_test: BenchmarkTestFiller, From 8811adddf1807e5b69151d5ed0c9b34afb42361b Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Thu, 25 Sep 2025 16:43:21 +0800 Subject: [PATCH 08/18] refactor: remove blockchain filler in worst block cases --- tests/benchmark/test_worst_blocks.py | 242 +++++++++++++++------------ 1 file changed, 137 insertions(+), 105 deletions(-) diff --git a/tests/benchmark/test_worst_blocks.py b/tests/benchmark/test_worst_blocks.py index 35b5150510d..91efec4d26d 100755 --- a/tests/benchmark/test_worst_blocks.py +++ b/tests/benchmark/test_worst_blocks.py @@ -2,6 +2,7 @@ Tests that benchmark EVMs in worst-case block scenarios. """ +import math import random from typing import Generator, Tuple @@ -14,11 +15,11 @@ Address, Alloc, AuthorizationTuple, + BenchmarkTestFiller, Block, BlockchainTestFiller, Environment, Hash, - StateTestFiller, Transaction, ) from ethereum_test_vm import Opcodes as Op @@ -114,7 +115,7 @@ def ether_transfer_case( ["a_to_a", "a_to_b", "diff_acc_to_b", "a_to_diff_acc", "diff_acc_to_diff_acc"], ) def test_block_full_of_ether_transfers( - blockchain_test: BlockchainTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, env: Environment, case_id: str, @@ -158,8 +159,7 @@ def test_block_full_of_ether_transfers( else {receiver: Account(balance=balance) for receiver, balance in balances.items()} ) - blockchain_test( - genesis_environment=env, + benchmark_test( pre=pre, post=post_state, blocks=[Block(txs=txs)], @@ -179,18 +179,14 @@ def total_cost_standard_per_token() -> int: return 4 -@pytest.mark.parametrize("zero_byte", [True, False]) -def test_block_full_data( - state_test: StateTestFiller, - pre: Alloc, - zero_byte: bool, - intrinsic_cost: int, +def calldata_generator( + gas_amount: int, + zero_byte: int, total_cost_floor_per_token: int, - gas_benchmark_value: int, -) -> None: - """Test a block with empty payload.""" - # Gas cost calculation based on EIP-7683: - # (https://eips.ethereum.org/EIPS/eip-7683) + total_cost_standard_per_token: int, +): + """Calculate the calldata based on the gas amount and zero byte.""" + # Gas cost calculation based on EIP-7683: (https://eips.ethereum.org/EIPS/eip-7683) # # tx.gasUsed = 21000 + max( # STANDARD_TOKEN_COST * tokens_in_calldata @@ -213,125 +209,161 @@ def test_block_full_data( # Token accounting: # tokens_in_calldata = zero_bytes + 4 * non_zero_bytes # - # So we calculate how many bytes we can fit into calldata based on - # available gas. - - gas_available = gas_benchmark_value - intrinsic_cost - - # Calculate the token_in_calldata - max_tokens_in_calldata = gas_available // total_cost_floor_per_token - # Calculate the number of bytes that can be stored in the calldata + # So we calculate how many bytes we can fit into calldata based on available gas. + max_tokens_in_calldata = gas_amount // total_cost_floor_per_token num_of_bytes = max_tokens_in_calldata if zero_byte else max_tokens_in_calldata // 4 byte_data = b"\x00" if zero_byte else b"\xff" + return byte_data * num_of_bytes - tx = Transaction( - to=pre.fund_eoa(), - data=byte_data * num_of_bytes, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - state_test( +@pytest.mark.parametrize("zero_byte", [True, False]) +def test_block_full_data( + benchmark_test: BenchmarkTestFiller, + pre: Alloc, + zero_byte: bool, + intrinsic_cost: int, + total_cost_floor_per_token: int, + gas_benchmark_value: int, + tx_gas_limit_cap: int, + total_cost_standard_per_token: int, + fork: Fork, +): + """Test a block with empty payload.""" + iteration_count = math.ceil(gas_benchmark_value / tx_gas_limit_cap) + + gas_remaining = gas_benchmark_value + total_gas_used = 0 + txs = [] + for _ in range(iteration_count): + gas_available = min(tx_gas_limit_cap, gas_remaining) - intrinsic_cost + data = calldata_generator( + gas_available, + zero_byte, + total_cost_floor_per_token, + total_cost_standard_per_token, + ) + + total_gas_used += fork.transaction_intrinsic_cost_calculator()(calldata=data) + gas_remaining -= gas_available + intrinsic_cost + + txs.append( + Transaction( + to=pre.fund_eoa(), + data=data, + gas_limit=gas_available + intrinsic_cost, + sender=pre.fund_eoa(), + ) + ) + + benchmark_test( pre=pre, post={}, - tx=tx, + blocks=[Block(txs=txs)], + expected_benchmark_gas_used=total_gas_used, ) def test_block_full_access_list_and_data( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, intrinsic_cost: int, total_cost_standard_per_token: int, fork: Fork, gas_benchmark_value: int, -) -> None: - """ - Test a block with access lists (60% gas) and calldata (40% gas) using - random mixed bytes. - """ - attack_gas_limit = gas_benchmark_value - gas_available = attack_gas_limit - intrinsic_cost + tx_gas_limit_cap: int, +): + """Test a block with access lists (60% gas) and calldata (40% gas) using random mixed bytes.""" + iteration_count = math.ceil(gas_benchmark_value / tx_gas_limit_cap) - # Split available gas: 60% for access lists, 40% for calldata - gas_for_access_list = int(gas_available * 0.6) - gas_for_calldata = int(gas_available * 0.4) + gas_remaining = gas_benchmark_value + total_gas_used = 0 - # Access list gas costs from fork's gas_costs - gas_costs = fork.gas_costs() - gas_per_address = gas_costs.G_ACCESS_LIST_ADDRESS - gas_per_storage_key = gas_costs.G_ACCESS_LIST_STORAGE - - # Calculate number of storage keys we can fit - gas_after_address = gas_for_access_list - gas_per_address - num_storage_keys = gas_after_address // gas_per_storage_key - - # Create access list with 1 address and many storage keys - access_address = Address("0x1234567890123456789012345678901234567890") - storage_keys = [] - for i in range(num_storage_keys): - # Generate random-looking storage keys - storage_keys.append(Hash(i)) - - access_list = [ - AccessList( - address=access_address, - storage_keys=storage_keys, - ) - ] + txs = [] + for _ in range(iteration_count): + gas_available = min(tx_gas_limit_cap, gas_remaining) - intrinsic_cost + + # Split available gas: 60% for access lists, 40% for calldata + gas_for_access_list = int(gas_available * 0.6) + gas_for_calldata = int(gas_available * 0.4) + + # Access list gas costs from fork's gas_costs + gas_costs = fork.gas_costs() + gas_per_address = gas_costs.G_ACCESS_LIST_ADDRESS + gas_per_storage_key = gas_costs.G_ACCESS_LIST_STORAGE + + # Calculate number of storage keys we can fit + gas_after_address = gas_for_access_list - gas_per_address + num_storage_keys = gas_after_address // gas_per_storage_key + + # Create access list with 1 address and many storage keys + access_address = Address("0x1234567890123456789012345678901234567890") + storage_keys = [] + for i in range(num_storage_keys): + # Generate random-looking storage keys + storage_keys.append(Hash(i)) + + access_list = [ + AccessList( + address=access_address, + storage_keys=storage_keys, + ) + ] - # Calculate calldata with 29% of gas for zero bytes and 71% for non-zero - # bytes - # Token accounting: tokens_in_calldata = zero_bytes + 4 * non_zero_bytes - # We want to split the gas budget: - # - 29% of gas_for_calldata for zero bytes - # - 71% of gas_for_calldata for non-zero bytes + # Calculate calldata with 29% of gas for zero bytes and 71% for non-zero bytes + # Token accounting: tokens_in_calldata = zero_bytes + 4 * non_zero_bytes + # We want to split the gas budget: + # - 29% of gas_for_calldata for zero bytes + # - 71% of gas_for_calldata for non-zero bytes - max_tokens_in_calldata = gas_for_calldata // total_cost_standard_per_token + max_tokens_in_calldata = gas_for_calldata // total_cost_standard_per_token - # Calculate how many tokens to allocate to each type - tokens_for_zero_bytes = int(max_tokens_in_calldata * 0.29) - tokens_for_non_zero_bytes = max_tokens_in_calldata - tokens_for_zero_bytes + # Calculate how many tokens to allocate to each type + tokens_for_zero_bytes = int(max_tokens_in_calldata * 0.29) + tokens_for_non_zero_bytes = max_tokens_in_calldata - tokens_for_zero_bytes - # Convert tokens to actual byte counts - # Zero bytes: 1 token per byte - # Non-zero bytes: 4 tokens per byte - num_zero_bytes = tokens_for_zero_bytes # 1 token = 1 zero byte - # 4 tokens = 1 non-zero byte - num_non_zero_bytes = tokens_for_non_zero_bytes // 4 + # Convert tokens to actual byte counts + # Zero bytes: 1 token per byte + # Non-zero bytes: 4 tokens per byte + num_zero_bytes = tokens_for_zero_bytes # 1 token = 1 zero byte + num_non_zero_bytes = tokens_for_non_zero_bytes // 4 # 4 tokens = 1 non-zero byte - # Create calldata with mixed bytes - calldata = bytearray() + # Create calldata with mixed bytes + calldata = bytearray() - # Add zero bytes - calldata.extend(b"\x00" * num_zero_bytes) + # Add zero bytes + calldata.extend(b"\x00" * num_zero_bytes) - # Add non-zero bytes (random values from 0x01 to 0xff) - rng = random.Random(42) # For reproducibility - for _ in range(num_non_zero_bytes): - calldata.append(rng.randint(1, 255)) + # Add non-zero bytes (random values from 0x01 to 0xff) + rng = random.Random(42) # For reproducibility + for _ in range(num_non_zero_bytes): + calldata.append(rng.randint(1, 255)) - # Shuffle the bytes to mix zero and non-zero bytes - calldata_list = list(calldata) - rng.shuffle(calldata_list) - shuffled_calldata = bytes(calldata_list) + # Shuffle the bytes to mix zero and non-zero bytes + calldata_list = list(calldata) + rng.shuffle(calldata_list) + shuffled_calldata = bytes(calldata_list) - tx = Transaction( - to=pre.fund_eoa(amount=0), - data=shuffled_calldata, - gas_limit=attack_gas_limit, - sender=pre.fund_eoa(), - access_list=access_list, - ) + txs.append( + Transaction( + to=pre.fund_eoa(amount=0), + data=shuffled_calldata, + gas_limit=gas_available + intrinsic_cost, + sender=pre.fund_eoa(), + access_list=access_list, + ) + ) - state_test( - pre=pre, - post={}, - tx=tx, - expected_benchmark_gas_used=fork.transaction_intrinsic_cost_calculator()( + gas_remaining -= gas_for_access_list + intrinsic_cost + total_gas_used += fork.transaction_intrinsic_cost_calculator()( calldata=shuffled_calldata, access_list=access_list, - ), + ) + + benchmark_test( + pre=pre, + post={}, + blocks=[Block(txs=txs)], + expected_benchmark_gas_used=total_gas_used, ) From 2215a496ef6350c138bba48f9ca20b678251612b Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Thu, 25 Sep 2025 16:43:54 +0800 Subject: [PATCH 09/18] refactor: update blockhash case --- .../benchmark/test_worst_stateful_opcodes.py | 43 +++++++++++++------ 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/tests/benchmark/test_worst_stateful_opcodes.py b/tests/benchmark/test_worst_stateful_opcodes.py index bcdd2bbdc45..8b962f5211a 100755 --- a/tests/benchmark/test_worst_stateful_opcodes.py +++ b/tests/benchmark/test_worst_stateful_opcodes.py @@ -9,7 +9,7 @@ from ethereum_test_benchmark.benchmark_code_generator import ExtCallGenerator, JumpLoopGenerator from ethereum_test_forks import Fork -from ethereum_test_specs import BlockchainTestFiller, StateTestFiller +from ethereum_test_specs import StateTestFiller from ethereum_test_specs.benchmark import BenchmarkTestFiller from ethereum_test_tools import ( Account, @@ -429,10 +429,12 @@ def test_worst_storage_access_warm( def test_worst_blockhash( - blockchain_test: BlockchainTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, + fork: Fork, gas_benchmark_value: int, -) -> None: + tx_gas_limit_cap: int, +): """ Test running a block with as many blockhash accessing oldest allowed block as possible. @@ -440,19 +442,32 @@ def test_worst_blockhash( # Create 256 dummy blocks to fill the blockhash window. blocks = [Block()] * 256 - # Always ask for the oldest allowed BLOCKHASH block. - execution_code = Op.PUSH1(1) + While( - body=Op.POP(Op.BLOCKHASH(Op.DUP1)), + code = ExtCallGenerator(setup=Bytecode(), attack_block=Op.BLOCKHASH(0)).generate_repeated_code( + repeated_code=Op.BLOCKHASH(1), + setup=Bytecode(), + cleanup=Bytecode(), + fork=fork, ) - execution_code_address = pre.deploy_contract(code=execution_code) - op_tx = Transaction( - to=execution_code_address, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - blocks.append(Block(txs=[op_tx])) - blockchain_test( + iteration_count = math.ceil(gas_benchmark_value / tx_gas_limit_cap) + code_address = pre.deploy_contract(code=code) + + txs = [] + for i in range(iteration_count): + tx_gas_limit = ( + tx_gas_limit_cap + if i != iteration_count - 1 + else gas_benchmark_value % tx_gas_limit_cap + ) + tx = Transaction( + to=code_address, + gas_limit=tx_gas_limit, + sender=pre.fund_eoa(), + ) + txs.append(tx) + blocks.append(Block(txs=txs)) + + benchmark_test( pre=pre, post={}, blocks=blocks, From afb15299dad55895c283d9dfc7f03a0ea6014e72 Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Thu, 25 Sep 2025 20:59:15 +0800 Subject: [PATCH 10/18] fix: resolve failing blob and block has tests --- tests/benchmark/test_worst_compute.py | 3 +++ tests/benchmark/test_worst_stateful_opcodes.py | 16 ++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/tests/benchmark/test_worst_compute.py b/tests/benchmark/test_worst_compute.py index c7be6c449c3..bcada7cdc33 100755 --- a/tests/benchmark/test_worst_compute.py +++ b/tests/benchmark/test_worst_compute.py @@ -1691,6 +1691,9 @@ def test_worst_blobhash( if blobs_present > 0: tx.ty = HexNumber(TransactionType.BLOB_TRANSACTION) tx.max_fee_per_blob_gas = HexNumber(fork.min_base_fee_per_blob_gas()) + tx.max_fee_per_gas = HexNumber(1000) + tx.max_priority_fee_per_gas = HexNumber(0) + tx.access_list = [] tx.blob_versioned_hashes = add_kzg_version( [i.to_bytes() * 32 for i in range(blobs_present)], BlobsSpec.BLOB_COMMITMENT_VERSION_KZG, diff --git a/tests/benchmark/test_worst_stateful_opcodes.py b/tests/benchmark/test_worst_stateful_opcodes.py index 8b962f5211a..428aaddbae6 100755 --- a/tests/benchmark/test_worst_stateful_opcodes.py +++ b/tests/benchmark/test_worst_stateful_opcodes.py @@ -7,6 +7,7 @@ import pytest +from ethereum_test_base_types import HexNumber from ethereum_test_benchmark.benchmark_code_generator import ExtCallGenerator, JumpLoopGenerator from ethereum_test_forks import Fork from ethereum_test_specs import StateTestFiller @@ -442,7 +443,7 @@ def test_worst_blockhash( # Create 256 dummy blocks to fill the blockhash window. blocks = [Block()] * 256 - code = ExtCallGenerator(setup=Bytecode(), attack_block=Op.BLOCKHASH(0)).generate_repeated_code( + code = ExtCallGenerator(setup=Bytecode(), attack_block=Op.BLOCKHASH(1)).generate_repeated_code( repeated_code=Op.BLOCKHASH(1), setup=Bytecode(), cleanup=Bytecode(), @@ -452,16 +453,14 @@ def test_worst_blockhash( iteration_count = math.ceil(gas_benchmark_value / tx_gas_limit_cap) code_address = pre.deploy_contract(code=code) + gas_remaining = gas_benchmark_value txs = [] - for i in range(iteration_count): - tx_gas_limit = ( - tx_gas_limit_cap - if i != iteration_count - 1 - else gas_benchmark_value % tx_gas_limit_cap - ) + for _ in range(iteration_count): + tx_gas_limit = min(tx_gas_limit_cap, gas_remaining) + gas_remaining -= tx_gas_limit tx = Transaction( to=code_address, - gas_limit=tx_gas_limit, + gas_limit=HexNumber(tx_gas_limit), sender=pre.fund_eoa(), ) txs.append(tx) @@ -471,6 +470,7 @@ def test_worst_blockhash( pre=pre, post={}, blocks=blocks, + expected_benchmark_gas_used=gas_benchmark_value, ) From 3cfa72320cba1846fa69b663003a356377a5270a Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Fri, 26 Sep 2025 13:59:29 +0800 Subject: [PATCH 11/18] fix: update linting comment length --- .../benchmark_code_generator.py | 4 +- tests/benchmark/test_worst_blocks.py | 14 ++-- tests/benchmark/test_worst_compute.py | 69 +++++++++---------- tests/benchmark/test_worst_memory.py | 31 ++++++--- .../benchmark/test_worst_stateful_opcodes.py | 10 ++- 5 files changed, 72 insertions(+), 56 deletions(-) diff --git a/src/ethereum_test_benchmark/benchmark_code_generator.py b/src/ethereum_test_benchmark/benchmark_code_generator.py index b81af44cf5a..5a8e8a953c6 100644 --- a/src/ethereum_test_benchmark/benchmark_code_generator.py +++ b/src/ethereum_test_benchmark/benchmark_code_generator.py @@ -17,7 +17,9 @@ class JumpLoopGenerator(BenchmarkCodeGenerator): def deploy_contracts(self, pre: Alloc, fork: Fork) -> Address: """Deploy the looping contract.""" # Benchmark Test Structure: - # setup + JUMPDEST + attack + attack + ... + cleanup + JUMP(setup_length) + # setup + JUMPDEST + + # attack + attack + ... + attack + + # cleanup + JUMP(setup_length) code = self.generate_repeated_code(self.attack_block, self.setup, self.cleanup, fork) self._contract_address = pre.deploy_contract(code=code) return self._contract_address diff --git a/tests/benchmark/test_worst_blocks.py b/tests/benchmark/test_worst_blocks.py index 91efec4d26d..7bdb66c37eb 100755 --- a/tests/benchmark/test_worst_blocks.py +++ b/tests/benchmark/test_worst_blocks.py @@ -209,7 +209,8 @@ def calldata_generator( # Token accounting: # tokens_in_calldata = zero_bytes + 4 * non_zero_bytes # - # So we calculate how many bytes we can fit into calldata based on available gas. + # So we calculate how many bytes we can fit into calldata based on + # available gas. max_tokens_in_calldata = gas_amount // total_cost_floor_per_token num_of_bytes = max_tokens_in_calldata if zero_byte else max_tokens_in_calldata // 4 byte_data = b"\x00" if zero_byte else b"\xff" @@ -272,7 +273,10 @@ def test_block_full_access_list_and_data( gas_benchmark_value: int, tx_gas_limit_cap: int, ): - """Test a block with access lists (60% gas) and calldata (40% gas) using random mixed bytes.""" + """ + Test a block with access lists (60% gas) and calldata (40% gas) using + random mixed bytes. + """ iteration_count = math.ceil(gas_benchmark_value / tx_gas_limit_cap) gas_remaining = gas_benchmark_value @@ -309,8 +313,10 @@ def test_block_full_access_list_and_data( ) ] - # Calculate calldata with 29% of gas for zero bytes and 71% for non-zero bytes - # Token accounting: tokens_in_calldata = zero_bytes + 4 * non_zero_bytes + # Calculate calldata with 29% of gas for zero bytes and 71% for + # non-zero bytes + # Token accounting: tokens_in_calldata = zero_bytes + 4 * + # non_zero_bytes # We want to split the gas budget: # - 29% of gas_for_calldata for zero bytes # - 71% of gas_for_calldata for non-zero bytes diff --git a/tests/benchmark/test_worst_compute.py b/tests/benchmark/test_worst_compute.py index bcada7cdc33..a2e49d58057 100755 --- a/tests/benchmark/test_worst_compute.py +++ b/tests/benchmark/test_worst_compute.py @@ -215,31 +215,12 @@ def test_worst_returndatasize_nonzero( def test_worst_returndatasize_zero( benchmark_test: BenchmarkTestFiller, pre: Alloc, - fork: Fork, - gas_benchmark_value: int, -) -> None: +): """ - Test running a block with as many RETURNDATASIZE opcodes as possible with a - zero buffer. + Test running a block with as many RETURNDATASIZE opcodes as possible with + a zero buffer. """ - max_code_size = fork.max_code_size() - - dummy_contract_call = Bytecode() - - code_prefix = dummy_contract_call + Op.JUMPDEST - iter_loop = Op.POP(Op.RETURNDATASIZE) - code_suffix = Op.JUMP(len(code_prefix) - 1) - code_iter_len = (max_code_size - len(code_prefix) - len(code_suffix)) // len(iter_loop) - code = code_prefix + iter_loop * code_iter_len + code_suffix - assert len(code) <= max_code_size - - tx = Transaction( - to=pre.deploy_contract(code=bytes(code)), - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( + benchmark_test( pre=pre, post={}, code_generator=ExtCallGenerator(setup=Bytecode(), attack_block=Op.RETURNDATASIZE), @@ -288,8 +269,10 @@ def test_worst_keccak( gsc = fork.gas_costs() mem_exp_gas_calculator = fork.memory_expansion_gas_calculator() - # Discover the optimal input size to maximize keccak-permutations, not keccak calls. - # The complication of the discovery arises from the non-linear gas cost of memory expansion. + # Discover the optimal input size to maximize keccak-permutations, + # not to maximize keccak calls. + # The complication of the discovery arises from + # the non-linear gas cost of memory expansion. max_keccak_perm_per_block = 0 optimal_input_length = 0 for i in range(1, 1_000_000, 32): @@ -320,9 +303,11 @@ def test_worst_keccak( # The loop structure is: JUMPDEST + [attack iteration] + PUSH0 + JUMP # # Now calculate available gas for [attack iteration]: - # Numerator = max_code_size-3. The -3 is for the JUMPDEST, PUSH0 and JUMP. - # Denominator = (PUSHN + PUSH1 + KECCAK256 + POP) + PUSH1_DATA + PUSHN_DATA - # TODO: the testing framework uses PUSH1(0) instead of PUSH0 which is suboptimal for the + # Numerator = max_code_size-3. (JUMPDEST, PUSH0 and JUMP) + # Denominator = (PUSHN + PUSH1 + KECCAK256 + POP) + PUSH1_DATA + + # PUSHN_DATA + # TODO: the testing framework uses PUSH1(0) instead of PUSH0 which is + # suboptimal for the # attack, whenever this is fixed adjust accordingly. benchmark_test( pre=pre, @@ -1566,11 +1551,13 @@ def test_worst_tstore( init_key = 42 setup = Op.PUSH1(init_key) - # If `dense_val_mut` is set, we use GAS as a cheap way of always storing a different value than + # If `dense_val_mut` is set, we use GAS as a cheap way of always + # storing a different value than # the previous one. attack_block = Op.TSTORE(Op.DUP2, Op.GAS if dense_val_mut else Op.DUP1) - # If `key_mut` is True, we mutate the key on every iteration of the big loop. + # If `key_mut` is True, we mutate the key on every iteration of the + # big loop. cleanup = Op.POP + Op.GAS if key_mut else Bytecode() benchmark_test( @@ -1731,8 +1718,10 @@ def test_worst_mod( The order of accessing the numerators is selected in a way the mod value remains in the range as long as possible. """ - # For SMOD we negate both numerator and modulus. The underlying computation is the same, - # just the SMOD implementation will have to additionally handle the sign bits. + # For SMOD we negate both numerator and modulus. The underlying + # computation is the same, + # just the SMOD implementation will have to additionally handle the + # sign bits. # The result stays negative. should_negate = op == Op.SMOD @@ -1804,7 +1793,8 @@ def test_worst_mod( seed += 1 print(f"{seed=}") - # TODO: Don't use fixed PUSH32. Let Bytecode helpers to select optimal push opcode. + # TODO: Don't use fixed PUSH32. Let Bytecode helpers to select optimal + # push opcode. setup = sum((Op.PUSH32[n] for n in numerators), Bytecode()) attack_block = ( Op.CALLDATALOAD(0) + sum(make_dup(len(numerators) - i) + op for i in indexes) + Op.POP @@ -1835,8 +1825,11 @@ def test_worst_memory_access( offset: int, offset_initialized: bool, big_memory_expansion: bool, -) -> None: - """Test running a block with as many memory access instructions as possible.""" +): + """ + Test running a block with as many memory access instructions as + possible. + """ mem_exp_code = Op.MSTORE8(10 * 1024, 1) if big_memory_expansion else Bytecode() offset_set_code = Op.MSTORE(offset, 43) if offset_initialized else Bytecode() setup = mem_exp_code + offset_set_code + Op.PUSH1(42) + Op.PUSH1(offset) @@ -2295,11 +2288,11 @@ def test_worst_clz_diff_input( pre: Alloc, fork: Fork, env: Environment, -) -> None: +): """ - Test running a block with as many CLZ with different input as possible. + Test running a block with as many CLZ with different input as + possible. """ - tx_gas_limit = fork.transaction_gas_limit_cap() or env.gas_limit max_code_size = fork.max_code_size() code_prefix = Op.JUMPDEST diff --git a/tests/benchmark/test_worst_memory.py b/tests/benchmark/test_worst_memory.py index 19da8842aac..6e114de7e66 100755 --- a/tests/benchmark/test_worst_memory.py +++ b/tests/benchmark/test_worst_memory.py @@ -82,10 +82,13 @@ def test_worst_calldatacopy( if min_gas > gas_benchmark_value: pytest.skip("Minimum gas required for calldata ({min_gas}) is greater than the gas limit") - # We create the contract that will be doing the CALLDATACOPY multiple times. + # We create the contract that will be doing the CALLDATACOPY multiple + # times. # - # If `non_zero_data` is True, we leverage CALLDATASIZE for the copy length. Otherwise, since we - # don't send zero data explicitly via calldata, PUSH the target size and use DUP1 to copy it. + # If `non_zero_data` is True, we leverage CALLDATASIZE for the copy + # length. Otherwise, since we + # don't send zero data explicitly via calldata, PUSH the target size and + # use DUP1 to copy it. setup = Bytecode() if non_zero_data or size == 0 else Op.PUSH3(size) src_dst = 0 if fixed_src_dst else Op.MOD(Op.GAS, 7) attack_block = Op.CALLDATACOPY( @@ -101,8 +104,8 @@ def test_worst_calldatacopy( # If the origin is CALL, we need to create a contract that will call the # target contract with the calldata. if origin == CallDataOrigin.CALL: - # If `non_zero_data` is False we leverage just using zeroed memory. Otherwise, we - # copy the calldata received from the transaction. + # If `non_zero_data` is False we leverage just using zeroed memory. + # Otherwise, we copy the calldata received from the transaction. setup = ( Op.CALLDATACOPY(Op.PUSH0, Op.PUSH0, Op.CALLDATASIZE) if non_zero_data else Bytecode() ) + Op.JUMPDEST @@ -166,8 +169,10 @@ def test_worst_codecopy( attack_block, Bytecode(), Bytecode(), fork ) - # The code generated above is not guaranteed to be of max_code_size, so we pad it since - # a test parameter targets CODECOPYing a contract with max code size. Padded bytecode values + # The code generated above is not guaranteed to be of max_code_size, so + # we pad it since + # a test parameter targets CODECOPYing a contract with max code size. + # Padded bytecode values # are not relevant. code += Op.INVALID * (max_code_size - len(code)) assert len(code) == max_code_size, ( @@ -209,8 +214,10 @@ def test_worst_returndatacopy( fixed_dst: bool, ): """Test running a block filled with RETURNDATACOPY executions.""" - # Create the contract that will RETURN the data that will be used for RETURNDATACOPY. - # Random-ish data is injected at different points in memory to avoid making the content + # Create the contract that will RETURN the data that will be used for + # RETURNDATACOPY. + # Random-ish data is injected at different points in memory to avoid + # making the content # predictable. If `size` is 0, this helper contract won't be used. code = ( Op.MSTORE8(0, Op.GAS) @@ -223,7 +230,8 @@ def test_worst_returndatacopy( returndata_gen = Op.STATICCALL(address=helper_contract) if size > 0 else Bytecode() dst = 0 if fixed_dst else Op.MOD(Op.GAS, 7) - # We create the contract that will be doing the RETURNDATACOPY multiple times. + # We create the contract that will be doing the RETURNDATACOPY multiple + # times. returndata_gen = Op.STATICCALL(address=helper_contract) if size > 0 else Bytecode() attack_block = Op.RETURNDATACOPY(dst, Op.PUSH0, Op.RETURNDATASIZE) @@ -236,7 +244,8 @@ def test_worst_returndatacopy( # STATICCALL(address=helper_contract) # JUMP(#) # ``` - # The goal is that once per (big) loop iteration, the helper contract is called to + # The goal is that once per (big) loop iteration, the helper contract is + # called to # generate fresh returndata to continue calling RETURNDATACOPY. benchmark_test( diff --git a/tests/benchmark/test_worst_stateful_opcodes.py b/tests/benchmark/test_worst_stateful_opcodes.py index 428aaddbae6..8bad73bbec8 100755 --- a/tests/benchmark/test_worst_stateful_opcodes.py +++ b/tests/benchmark/test_worst_stateful_opcodes.py @@ -140,7 +140,10 @@ def test_worst_address_state_warm( opcode: Op, absent_target: bool, ): - """Test running a block with as many stateful opcodes doing warm access for an account.""" + """ + Test running a block with as many stateful opcodes doing warm access + for an account. + """ # Setup target_addr = Address(100_000) post = {} @@ -374,7 +377,10 @@ def test_worst_storage_access_warm( gas_benchmark_value: int, env: Environment, ): - """Test running a block with as many warm storage slot accesses as possible.""" + """ + Test running a block with as many warm storage slot accesses as + possible. + """ blocks = [] # The target storage slot for the warm access is storage slot 0. From 8aa7eab9cdc99423e3f6efd66a479e16049b2c1f Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Fri, 10 Oct 2025 12:31:40 +0800 Subject: [PATCH 12/18] fix linting and typing issue --- tests/benchmark/test_worst_blocks.py | 11 ++---- tests/benchmark/test_worst_bytecode.py | 1 - tests/benchmark/test_worst_compute.py | 36 +++++++++---------- tests/benchmark/test_worst_memory.py | 6 ++-- tests/benchmark/test_worst_opcode.py | 2 +- .../benchmark/test_worst_stateful_opcodes.py | 8 ++--- 6 files changed, 27 insertions(+), 37 deletions(-) diff --git a/tests/benchmark/test_worst_blocks.py b/tests/benchmark/test_worst_blocks.py index 7bdb66c37eb..022e6ee0970 100755 --- a/tests/benchmark/test_worst_blocks.py +++ b/tests/benchmark/test_worst_blocks.py @@ -18,7 +18,6 @@ BenchmarkTestFiller, Block, BlockchainTestFiller, - Environment, Hash, Transaction, ) @@ -117,13 +116,11 @@ def ether_transfer_case( def test_block_full_of_ether_transfers( benchmark_test: BenchmarkTestFiller, pre: Alloc, - env: Environment, case_id: str, ether_transfer_case: Tuple[Generator[Address, None, None], Generator[Address, None, None]], iteration_count: int, transfer_amount: int, intrinsic_cost: int, - gas_benchmark_value: int, ) -> None: """ Single test for ether transfer scenarios. @@ -183,8 +180,7 @@ def calldata_generator( gas_amount: int, zero_byte: int, total_cost_floor_per_token: int, - total_cost_standard_per_token: int, -): +) -> bytes: """Calculate the calldata based on the gas amount and zero byte.""" # Gas cost calculation based on EIP-7683: (https://eips.ethereum.org/EIPS/eip-7683) # @@ -228,7 +224,7 @@ def test_block_full_data( tx_gas_limit_cap: int, total_cost_standard_per_token: int, fork: Fork, -): +) -> None: """Test a block with empty payload.""" iteration_count = math.ceil(gas_benchmark_value / tx_gas_limit_cap) @@ -241,7 +237,6 @@ def test_block_full_data( gas_available, zero_byte, total_cost_floor_per_token, - total_cost_standard_per_token, ) total_gas_used += fork.transaction_intrinsic_cost_calculator()(calldata=data) @@ -272,7 +267,7 @@ def test_block_full_access_list_and_data( fork: Fork, gas_benchmark_value: int, tx_gas_limit_cap: int, -): +) -> None: """ Test a block with access lists (60% gas) and calldata (40% gas) using random mixed bytes. diff --git a/tests/benchmark/test_worst_bytecode.py b/tests/benchmark/test_worst_bytecode.py index 85c2c49c405..fa20dc6f05d 100755 --- a/tests/benchmark/test_worst_bytecode.py +++ b/tests/benchmark/test_worst_bytecode.py @@ -343,7 +343,6 @@ def test_worst_create( max_code_size_ratio: float, non_zero_data: bool, value: int, - gas_benchmark_value: int, ) -> None: """ Test the CREATE and CREATE2 performance with different configurations. diff --git a/tests/benchmark/test_worst_compute.py b/tests/benchmark/test_worst_compute.py index a2e49d58057..d6d51a3b019 100755 --- a/tests/benchmark/test_worst_compute.py +++ b/tests/benchmark/test_worst_compute.py @@ -9,6 +9,7 @@ from typing import Any, cast import pytest +from _pytest.mark import ParameterSet from py_ecc.bn128 import G1, G2, multiply from ethereum_test_base_types.base_types import Bytes, HexNumber @@ -20,7 +21,6 @@ BenchmarkTestFiller, Block, Bytecode, - Environment, Transaction, add_kzg_version, ) @@ -82,8 +82,6 @@ def test_worst_zero_param( benchmark_test: BenchmarkTestFiller, pre: Alloc, opcode: Op, - fork: Fork, - gas_benchmark_value: int, ) -> None: """Test running a block with as many zero-parameter opcodes as possible.""" benchmark_test( @@ -122,7 +120,6 @@ def test_worst_callvalue( fork: Fork, non_zero_value: bool, from_origin: bool, - gas_benchmark_value: int, ) -> None: """ Test running a block with as many CALLVALUE opcodes as possible. @@ -180,7 +177,6 @@ def test_worst_returndatasize_nonzero( pre: Alloc, returned_size: int, return_data_style: ReturnDataStyle, - gas_benchmark_value: int, ) -> None: """ Test running a block which execute as many RETURNDATASIZE opcodes which @@ -215,7 +211,7 @@ def test_worst_returndatasize_nonzero( def test_worst_returndatasize_zero( benchmark_test: BenchmarkTestFiller, pre: Alloc, -): +) -> None: """ Test running a block with as many RETURNDATASIZE opcodes as possible with a zero buffer. @@ -395,7 +391,7 @@ def test_worst_precompile_only_data_input( ) -def create_modexp_test_cases(): +def create_modexp_test_cases() -> list[ParameterSet]: """Create test cases for the MODEXP precompile.""" test_cases = [ # (base, exponent, modulus, test_id) @@ -1195,7 +1191,6 @@ def test_worst_precompile_fixed_cost( fork: Fork, precompile_address: Address, parameters: list[str] | list[BytesConcatenation] | list[bytes], - gas_benchmark_value: int, ) -> None: """Test running a block filled with a precompile with fixed cost.""" if precompile_address not in fork.precompiles(): @@ -1546,7 +1541,7 @@ def test_worst_tstore( pre: Alloc, key_mut: bool, dense_val_mut: bool, -): +) -> None: """Test running a block with as many TSTORE calls as possible.""" init_key = 42 setup = Op.PUSH1(init_key) @@ -1825,7 +1820,7 @@ def test_worst_memory_access( offset: int, offset_initialized: bool, big_memory_expansion: bool, -): +) -> None: """ Test running a block with as many memory access instructions as possible. @@ -2070,12 +2065,18 @@ def test_worst_calldataload( benchmark_test: BenchmarkTestFiller, pre: Alloc, calldata: bytes, -): + gas_benchmark_value: int, + fork: Fork, +) -> None: """Test running a block with as many CALLDATALOAD as possible.""" + tx = JumpLoopGenerator(setup=Op.PUSH0, attack_block=Op.CALLDATALOAD).generate_transaction( + pre, gas_benchmark_value, fork + ) + tx.data = Bytes(calldata) benchmark_test( pre=pre, post={}, - code_generator=JumpLoopGenerator(setup=Op.PUSH0, attack_block=Op.CALLDATALOAD), + tx=tx, ) @@ -2141,7 +2142,7 @@ def test_worst_dup( pre: Alloc, fork: Fork, opcode: Op, -): +) -> None: """Test running a block with as many DUP as possible.""" max_stack_height = fork.max_stack_height() @@ -2200,7 +2201,7 @@ def test_worst_push( benchmark_test: BenchmarkTestFiller, pre: Alloc, opcode: Op, -): +) -> None: """Test running a block with as many PUSH as possible.""" benchmark_test( pre=pre, @@ -2232,7 +2233,6 @@ def test_worst_return_revert( opcode: Op, return_size: int, return_non_zero_data: bool, - gas_benchmark_value: int, ) -> None: """Test running a block with as many RETURN or REVERT as possible.""" max_code_size = fork.max_code_size() @@ -2268,9 +2268,6 @@ def test_worst_return_revert( def test_worst_clz_same_input( benchmark_test: BenchmarkTestFiller, pre: Alloc, - fork: Fork, - gas_benchmark_value: int, - env: Environment, ) -> None: """Test running a block with as many CLZ with same input as possible.""" magic_value = 248 # CLZ(248) = 248 @@ -2287,8 +2284,7 @@ def test_worst_clz_diff_input( benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, - env: Environment, -): +) -> None: """ Test running a block with as many CLZ with different input as possible. diff --git a/tests/benchmark/test_worst_memory.py b/tests/benchmark/test_worst_memory.py index 6e114de7e66..1077d84dad2 100755 --- a/tests/benchmark/test_worst_memory.py +++ b/tests/benchmark/test_worst_memory.py @@ -155,7 +155,7 @@ def test_worst_codecopy( fork: Fork, max_code_size_ratio: float, fixed_src_dst: bool, -): +) -> None: """Test running a block filled with CODECOPY executions.""" max_code_size = fork.max_code_size() @@ -212,7 +212,7 @@ def test_worst_returndatacopy( pre: Alloc, size: int, fixed_dst: bool, -): +) -> None: """Test running a block filled with RETURNDATACOPY executions.""" # Create the contract that will RETURN the data that will be used for # RETURNDATACOPY. @@ -278,7 +278,7 @@ def test_worst_mcopy( pre: Alloc, size: int, fixed_src_dst: bool, -): +) -> None: """Test running a block filled with MCOPY executions.""" src_dst = 0 if fixed_src_dst else Op.MOD(Op.GAS, 7) attack_block = Op.MCOPY(src_dst, src_dst, size) diff --git a/tests/benchmark/test_worst_opcode.py b/tests/benchmark/test_worst_opcode.py index 82479d4c9ec..8d4a87a3f90 100755 --- a/tests/benchmark/test_worst_opcode.py +++ b/tests/benchmark/test_worst_opcode.py @@ -44,7 +44,7 @@ def test_worst_log_opcodes( size: int, fixed_offset: bool, non_zero_data: bool, -): +) -> None: """Test running a block with as many LOG opcodes as possible.""" setup = Bytecode() diff --git a/tests/benchmark/test_worst_stateful_opcodes.py b/tests/benchmark/test_worst_stateful_opcodes.py index 8bad73bbec8..002a2b9833b 100755 --- a/tests/benchmark/test_worst_stateful_opcodes.py +++ b/tests/benchmark/test_worst_stateful_opcodes.py @@ -139,7 +139,7 @@ def test_worst_address_state_warm( pre: Alloc, opcode: Op, absent_target: bool, -): +) -> None: """ Test running a block with as many stateful opcodes doing warm access for an account. @@ -376,7 +376,7 @@ def test_worst_storage_access_warm( storage_action: StorageAction, gas_benchmark_value: int, env: Environment, -): +) -> None: """ Test running a block with as many warm storage slot accesses as possible. @@ -441,7 +441,7 @@ def test_worst_blockhash( fork: Fork, gas_benchmark_value: int, tx_gas_limit_cap: int, -): +) -> None: """ Test running a block with as many blockhash accessing oldest allowed block as possible. @@ -483,7 +483,7 @@ def test_worst_blockhash( def test_worst_selfbalance( benchmark_test: BenchmarkTestFiller, pre: Alloc, -): +) -> None: """Test running a block with as many SELFBALANCE opcodes as possible.""" benchmark_test( pre=pre, From d9c6441fd965084cd6f2000b0d77b8c63eb3130b Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Fri, 10 Oct 2025 14:52:57 +0800 Subject: [PATCH 13/18] fix incorrect logic for missing coverage --- src/ethereum_test_specs/benchmark.py | 4 +++- tests/benchmark/test_worst_bytecode.py | 2 +- tests/benchmark/test_worst_compute.py | 2 +- tests/benchmark/test_worst_memory.py | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/ethereum_test_specs/benchmark.py b/src/ethereum_test_specs/benchmark.py index d0b2fcd14e1..7cbb380dc23 100644 --- a/src/ethereum_test_specs/benchmark.py +++ b/src/ethereum_test_specs/benchmark.py @@ -66,7 +66,9 @@ def generate_repeated_code( available_space = max_code_size - overhead max_iterations = available_space // len(repeated_code) - code = setup + Op.JUMPDEST + repeated_code * max_iterations + cleanup + Op.JUMP(len(setup)) + # TODO: Unify the PUSH0 and PUSH1 usage. + code = setup + Op.JUMPDEST + repeated_code * max_iterations + cleanup + code += Op.JUMP(len(setup)) if len(setup) > 0 else Op.PUSH0 + Op.JUMP self._validate_code_size(code, fork) return code diff --git a/tests/benchmark/test_worst_bytecode.py b/tests/benchmark/test_worst_bytecode.py index fa20dc6f05d..a949e4e8873 100755 --- a/tests/benchmark/test_worst_bytecode.py +++ b/tests/benchmark/test_worst_bytecode.py @@ -408,7 +408,7 @@ def test_worst_create( ) code = JumpLoopGenerator(setup=setup, attack_block=attack_block).generate_repeated_code( - attack_block, Bytecode(), Bytecode(), fork + repeated_code=attack_block, setup=setup, cleanup=Bytecode(), fork=fork ) tx = Transaction( diff --git a/tests/benchmark/test_worst_compute.py b/tests/benchmark/test_worst_compute.py index d6d51a3b019..7f877828292 100755 --- a/tests/benchmark/test_worst_compute.py +++ b/tests/benchmark/test_worst_compute.py @@ -101,7 +101,7 @@ def test_worst_calldatasize( ) -> None: """Test running a block with as many CALLDATASIZE as possible.""" tx = JumpLoopGenerator( - setup=Bytecode(), attack_block=Op.POP(Op.CALLDATASIZE) + setup=Bytecode(), attack_block=Op.POP(Op.CALLDATASIZE), cleanup=Bytecode() ).generate_transaction(pre, gas_benchmark_value, fork) tx.data = Bytes(b"\x00" * calldata_length) diff --git a/tests/benchmark/test_worst_memory.py b/tests/benchmark/test_worst_memory.py index 1077d84dad2..116f3a9551f 100755 --- a/tests/benchmark/test_worst_memory.py +++ b/tests/benchmark/test_worst_memory.py @@ -166,7 +166,7 @@ def test_worst_codecopy( attack_block = Op.CODECOPY(src_dst, src_dst, Op.DUP1) # DUP1 copies size. code = JumpLoopGenerator(setup=setup, attack_block=attack_block).generate_repeated_code( - attack_block, Bytecode(), Bytecode(), fork + repeated_code=attack_block, setup=setup, cleanup=Bytecode(), fork=fork ) # The code generated above is not guaranteed to be of max_code_size, so From 1d51ff5fef998068aa1efda309059d7848e2c20c Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Fri, 10 Oct 2025 23:15:14 +0800 Subject: [PATCH 14/18] refactor unop worst case --- tests/benchmark/test_worst_compute.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/benchmark/test_worst_compute.py b/tests/benchmark/test_worst_compute.py index 7f877828292..cf66584ac6f 100755 --- a/tests/benchmark/test_worst_compute.py +++ b/tests/benchmark/test_worst_compute.py @@ -1457,7 +1457,7 @@ def test_worst_binop_simple( setup = Op.CALLDATALOAD(0) + Op.CALLDATALOAD(32) + Op.DUP2 + Op.DUP2 attack_block = Op.DUP2 + opcode - cleanup = Op.POP + Op.POP + cleanup = Op.POP + Op.POP + Op.DUP2 + Op.DUP2 tx = JumpLoopGenerator( setup=setup, attack_block=attack_block, cleanup=cleanup ).generate_transaction(pre, gas_benchmark_value, fork) @@ -1483,9 +1483,7 @@ def test_worst_unop( benchmark_test( pre=pre, post={}, - code_generator=JumpLoopGenerator( - setup=Op.PUSH0, attack_block=opcode, cleanup=Op.POP + Op.PUSH0 - ), + code_generator=JumpLoopGenerator(setup=Op.PUSH0, attack_block=opcode), ) From 454bdd60af6426dde2a0737ac256a815f5594ffa Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Fri, 10 Oct 2025 21:56:31 +0000 Subject: [PATCH 15/18] refactor(tests/benchmark): Optimize generators usages --- .../benchmark_code_generator.py | 46 ++- src/ethereum_test_specs/benchmark.py | 49 +++- tests/benchmark/test_worst_blocks.py | 4 - tests/benchmark/test_worst_bytecode.py | 26 +- tests/benchmark/test_worst_compute.py | 276 +++++------------- tests/benchmark/test_worst_memory.py | 23 +- tests/benchmark/test_worst_opcode.py | 4 - .../benchmark/test_worst_stateful_opcodes.py | 33 +-- 8 files changed, 148 insertions(+), 313 deletions(-) diff --git a/src/ethereum_test_benchmark/benchmark_code_generator.py b/src/ethereum_test_benchmark/benchmark_code_generator.py index 5a8e8a953c6..7061acdd0f3 100644 --- a/src/ethereum_test_benchmark/benchmark_code_generator.py +++ b/src/ethereum_test_benchmark/benchmark_code_generator.py @@ -3,46 +3,42 @@ optimized bytecode patterns. """ +from dataclasses import dataclass + from ethereum_test_base_types import Address from ethereum_test_forks import Fork from ethereum_test_specs.benchmark import BenchmarkCodeGenerator -from ethereum_test_types import Alloc, Transaction -from ethereum_test_vm import Bytecode +from ethereum_test_types import Alloc from ethereum_test_vm.opcodes import Opcodes as Op +@dataclass(kw_only=True) class JumpLoopGenerator(BenchmarkCodeGenerator): """Generates bytecode that loops execution using JUMP operations.""" - def deploy_contracts(self, pre: Alloc, fork: Fork) -> Address: + def deploy_contracts(self, *, pre: Alloc, fork: Fork) -> Address: """Deploy the looping contract.""" # Benchmark Test Structure: # setup + JUMPDEST + # attack + attack + ... + attack + # cleanup + JUMP(setup_length) - code = self.generate_repeated_code(self.attack_block, self.setup, self.cleanup, fork) + code = self.generate_repeated_code( + repeated_code=self.attack_block, setup=self.setup, cleanup=self.cleanup, fork=fork + ) self._contract_address = pre.deploy_contract(code=code) return self._contract_address - def generate_transaction(self, pre: Alloc, gas_limit: int) -> Transaction: - """Generate transaction that executes the looping contract.""" - if not hasattr(self, "_contract_address"): - self.deploy_contracts(pre, fork) - - return Transaction( - to=self._contract_address, - gas_limit=gas_limit, - sender=pre.fund_eoa(), - ) - +@dataclass(kw_only=True) class ExtCallGenerator(BenchmarkCodeGenerator): """ Generates bytecode that fills the contract to maximum allowed code size. """ - def deploy_contracts(self, pre: Alloc, fork: Fork) -> Address: + contract_balance: int = 0 + + def deploy_contracts(self, *, pre: Alloc, fork: Fork) -> Address: """Deploy both target and caller contracts.""" # Benchmark Test Structure: # There are two contracts: @@ -56,7 +52,8 @@ def deploy_contracts(self, pre: Alloc, fork: Fork) -> Address: # Deploy target contract that contains the actual attack block self._target_contract_address = pre.deploy_contract( - code=self.setup + self.attack_block * max_iterations + code=self.setup + self.attack_block * max_iterations, + balance=self.contract_balance, ) # Create caller contract that repeatedly calls the target contract @@ -68,17 +65,8 @@ def deploy_contracts(self, pre: Alloc, fork: Fork) -> Address: # JUMP(setup_length) code_sequence = Op.POP(Op.STATICCALL(Op.GAS, self._target_contract_address, 0, 0, 0, 0)) - caller_code = self.generate_repeated_code(code_sequence, Bytecode(), self.cleanup, fork) + caller_code = self.generate_repeated_code( + repeated_code=code_sequence, cleanup=self.cleanup, fork=fork + ) self._contract_address = pre.deploy_contract(code=caller_code) return self._contract_address - - def generate_transaction(self, pre: Alloc, gas_limit: int) -> Transaction: - """Generate transaction that executes the caller contract.""" - if not hasattr(self, "_contract_address"): - self.deploy_contracts(pre, fork) - - return Transaction( - to=self._contract_address, - gas_limit=gas_limit, - sender=pre.fund_eoa(), - ) diff --git a/src/ethereum_test_specs/benchmark.py b/src/ethereum_test_specs/benchmark.py index 7cbb380dc23..2397a209eaa 100644 --- a/src/ethereum_test_specs/benchmark.py +++ b/src/ethereum_test_specs/benchmark.py @@ -3,7 +3,7 @@ import math from abc import ABC, abstractmethod from dataclasses import dataclass, field -from typing import Callable, ClassVar, Dict, Generator, List, Sequence, Type +from typing import Any, Callable, ClassVar, Dict, Generator, List, Sequence, Type import pytest from pydantic import ConfigDict, Field @@ -41,19 +41,33 @@ class BenchmarkCodeGenerator(ABC): attack_block: Bytecode setup: Bytecode = field(default_factory=Bytecode) cleanup: Bytecode = field(default_factory=Bytecode) + tx_kwargs: Dict[str, Any] = field(default_factory=dict) + _contract_address: Address | None = None @abstractmethod - def deploy_contracts(self, pre: Alloc, fork: Fork) -> Address: + def deploy_contracts(self, *, pre: Alloc, fork: Fork) -> Address: """Deploy any contracts needed for the benchmark.""" ... - @abstractmethod - def generate_transaction(self, pre: Alloc, gas_limit: int) -> Transaction: - """Generate a transaction with the specified gas limit.""" - ... + def generate_transaction(self, *, pre: Alloc, gas_benchmark_value: int) -> Transaction: + """Generate transaction that executes the looping contract.""" + assert self._contract_address is not None + if "gas_limit" not in self.tx_kwargs: + self.tx_kwargs["gas_limit"] = gas_benchmark_value + + return Transaction( + to=self._contract_address, + sender=pre.fund_eoa(), + **self.tx_kwargs, + ) def generate_repeated_code( - self, repeated_code: Bytecode, setup: Bytecode, cleanup: Bytecode, fork: Fork + self, + *, + repeated_code: Bytecode, + setup: Bytecode | None = None, + cleanup: Bytecode | None = None, + fork: Fork, ) -> Bytecode: """ Calculate the maximum number of iterations that @@ -61,7 +75,10 @@ def generate_repeated_code( """ assert len(repeated_code) > 0, "repeated_code cannot be empty" max_code_size = fork.max_code_size() - + if setup is None: + setup = Bytecode() + if cleanup is None: + cleanup = Bytecode() overhead = len(setup) + len(Op.JUMPDEST) + len(cleanup) + len(Op.JUMP(len(setup))) available_space = max_code_size - overhead max_iterations = available_space // len(repeated_code) @@ -87,7 +104,7 @@ class BenchmarkTest(BaseTest): model_config = ConfigDict(extra="forbid") - pre: Alloc + pre: Alloc = Field(default_factory=Alloc) post: Alloc = Field(default_factory=Alloc) tx: Transaction | None = None blocks: List[Block] | None = None @@ -118,6 +135,14 @@ class BenchmarkTest(BaseTest): "blockchain_test_only": "Only generate a blockchain test fixture", } + def model_post_init(self, __context: Any, /) -> None: + """ + Model post-init to assert that the custom pre-allocation was + provided and the default was not used. + """ + super().model_post_init(__context) + assert "pre" in self.model_fields_set, "pre allocation was not provided" + @classmethod def pytest_parameter_name(cls) -> str: """ @@ -181,9 +206,11 @@ def generate_blocks_from_code_generator(self, fork: Fork) -> List[Block]: if self.code_generator is None: raise Exception("Code generator is not set") - self.code_generator.deploy_contracts(self.pre, fork) + self.code_generator.deploy_contracts(pre=self.pre, fork=fork) gas_limit = fork.transaction_gas_limit_cap() or self.gas_benchmark_value - benchmark_tx = self.code_generator.generate_transaction(self.pre, gas_limit) + benchmark_tx = self.code_generator.generate_transaction( + pre=self.pre, gas_benchmark_value=gas_limit + ) execution_txs = self.split_transaction(benchmark_tx, gas_limit) execution_block = Block(txs=execution_txs) diff --git a/tests/benchmark/test_worst_blocks.py b/tests/benchmark/test_worst_blocks.py index 022e6ee0970..9e59c8b28f1 100755 --- a/tests/benchmark/test_worst_blocks.py +++ b/tests/benchmark/test_worst_blocks.py @@ -252,8 +252,6 @@ def test_block_full_data( ) benchmark_test( - pre=pre, - post={}, blocks=[Block(txs=txs)], expected_benchmark_gas_used=total_gas_used, ) @@ -361,8 +359,6 @@ def test_block_full_access_list_and_data( ) benchmark_test( - pre=pre, - post={}, blocks=[Block(txs=txs)], expected_benchmark_gas_used=total_gas_used, ) diff --git a/tests/benchmark/test_worst_bytecode.py b/tests/benchmark/test_worst_bytecode.py index a949e4e8873..612940a4394 100755 --- a/tests/benchmark/test_worst_bytecode.py +++ b/tests/benchmark/test_worst_bytecode.py @@ -15,7 +15,6 @@ Block, BlockchainTestFiller, Bytecode, - Bytes, Environment, Hash, Transaction, @@ -246,10 +245,8 @@ def test_worst_bytecode_single_opcode( ) def test_worst_initcode_jumpdest_analysis( benchmark_test: BenchmarkTestFiller, - pre: Alloc, fork: Fork, pattern: Bytecode, - gas_benchmark_value: int, ) -> None: """ Test the jumpdest analysis performance of the initcode. @@ -298,15 +295,12 @@ def test_worst_initcode_jumpdest_analysis( setup = code_prepare_initcode + Op.PUSH0 - tx = JumpLoopGenerator( - setup=setup, attack_block=attack_block, cleanup=Bytecode() - ).generate_transaction(pre, gas_benchmark_value, fork) - tx.data = Bytes(tx_data) - benchmark_test( - pre=pre, - post={}, - tx=tx, + code_generator=JumpLoopGenerator( + setup=setup, + attack_block=attack_block, + tx_kwargs={"data": tx_data}, + ), ) @@ -408,7 +402,7 @@ def test_worst_create( ) code = JumpLoopGenerator(setup=setup, attack_block=attack_block).generate_repeated_code( - repeated_code=attack_block, setup=setup, cleanup=Bytecode(), fork=fork + repeated_code=attack_block, setup=setup, fork=fork ) tx = Transaction( @@ -417,11 +411,7 @@ def test_worst_create( sender=pre.fund_eoa(), ) - benchmark_test( - pre=pre, - post={}, - tx=tx, - ) + benchmark_test(tx=tx) @pytest.mark.parametrize( @@ -483,7 +473,5 @@ def test_worst_creates_collisions( pre.deploy_contract(address=addr, code=Op.INVALID) benchmark_test( - pre=pre, - post={}, code_generator=JumpLoopGenerator(setup=setup, attack_block=attack_block), ) diff --git a/tests/benchmark/test_worst_compute.py b/tests/benchmark/test_worst_compute.py index cf66584ac6f..c1610c027fd 100755 --- a/tests/benchmark/test_worst_compute.py +++ b/tests/benchmark/test_worst_compute.py @@ -6,13 +6,13 @@ import operator import random from enum import Enum, auto -from typing import Any, cast +from typing import Any, Dict, cast import pytest from _pytest.mark import ParameterSet from py_ecc.bn128 import G1, G2, multiply -from ethereum_test_base_types.base_types import Bytes, HexNumber +from ethereum_test_base_types.base_types import Bytes from ethereum_test_benchmark import ExtCallGenerator, JumpLoopGenerator from ethereum_test_forks import Fork from ethereum_test_tools import ( @@ -87,28 +87,21 @@ def test_worst_zero_param( benchmark_test( pre=pre, post={}, - code_generator=ExtCallGenerator(setup=Bytecode(), attack_block=opcode), + code_generator=ExtCallGenerator(attack_block=opcode), ) @pytest.mark.parametrize("calldata_length", [0, 1_000, 10_000]) def test_worst_calldatasize( benchmark_test: BenchmarkTestFiller, - pre: Alloc, - fork: Fork, calldata_length: int, - gas_benchmark_value: int, ) -> None: """Test running a block with as many CALLDATASIZE as possible.""" - tx = JumpLoopGenerator( - setup=Bytecode(), attack_block=Op.POP(Op.CALLDATASIZE), cleanup=Bytecode() - ).generate_transaction(pre, gas_benchmark_value, fork) - tx.data = Bytes(b"\x00" * calldata_length) - benchmark_test( - pre=pre, - post={}, - tx=tx, + code_generator=JumpLoopGenerator( + attack_block=Op.POP(Op.CALLDATASIZE), + tx_kwargs={"data": b"\x00" * calldata_length}, + ), ) @@ -128,9 +121,9 @@ def test_worst_callvalue( value. The `from_origin` parameter controls whether the call frame is the immediate from the transaction or a previous CALL. """ - code_address = JumpLoopGenerator( - setup=Bytecode(), attack_block=Op.POP(Op.CALLVALUE), cleanup=Bytecode() - ).deploy_contracts(pre, fork) + code_address = JumpLoopGenerator(attack_block=Op.POP(Op.CALLVALUE)).deploy_contracts( + pre=pre, fork=fork + ) if from_origin: tx_to = code_address @@ -148,11 +141,7 @@ def test_worst_callvalue( sender=pre.fund_eoa(), ) - benchmark_test( - pre=pre, - post={}, - tx=tx, - ) + benchmark_test(tx=tx) class ReturnDataStyle(Enum): @@ -202,58 +191,41 @@ def test_worst_returndatasize_nonzero( ) benchmark_test( - pre=pre, - post={}, code_generator=JumpLoopGenerator(setup=setup, attack_block=Op.POP(Op.RETURNDATASIZE)), ) -def test_worst_returndatasize_zero( - benchmark_test: BenchmarkTestFiller, - pre: Alloc, -) -> None: +def test_worst_returndatasize_zero(benchmark_test: BenchmarkTestFiller) -> None: """ Test running a block with as many RETURNDATASIZE opcodes as possible with a zero buffer. """ benchmark_test( - pre=pre, - post={}, - code_generator=ExtCallGenerator(setup=Bytecode(), attack_block=Op.RETURNDATASIZE), + code_generator=ExtCallGenerator(attack_block=Op.RETURNDATASIZE), ) @pytest.mark.parametrize("mem_size", [0, 1, 1_000, 100_000, 1_000_000]) def test_worst_msize( benchmark_test: BenchmarkTestFiller, - pre: Alloc, - fork: Fork, mem_size: int, - gas_benchmark_value: int, ) -> None: """ Test running a block with as many MSIZE opcodes as possible. The `mem_size` parameter indicates by how much the memory is expanded. """ - generator = ExtCallGenerator( - setup=Op.MLOAD(Op.CALLVALUE) + Op.POP, - attack_block=Op.MSIZE, - ) - generator.deploy_contracts(pre, fork) - tx = generator.generate_transaction(pre, gas_benchmark_value, fork) - tx.value = HexNumber(mem_size) - benchmark_test( - pre=pre, - post={}, - tx=tx, + code_generator=ExtCallGenerator( + setup=Op.MLOAD(Op.CALLVALUE) + Op.POP, + attack_block=Op.MSIZE, + tx_kwargs={"value": mem_size}, + ), ) def test_worst_keccak( benchmark_test: BenchmarkTestFiller, - pre: Alloc, fork: Fork, gas_benchmark_value: int, ) -> None: @@ -306,12 +278,9 @@ def test_worst_keccak( # suboptimal for the # attack, whenever this is fixed adjust accordingly. benchmark_test( - pre=pre, - post={}, code_generator=JumpLoopGenerator( setup=Op.PUSH20[optimal_input_length], attack_block=Op.POP(Op.SHA3(Op.PUSH0, Op.DUP1)), - cleanup=Bytecode(), ), ) @@ -326,7 +295,6 @@ def test_worst_keccak( ) def test_worst_precompile_only_data_input( benchmark_test: BenchmarkTestFiller, - pre: Alloc, fork: Fork, address: Address, static_cost: int, @@ -383,8 +351,6 @@ def test_worst_precompile_only_data_input( attack_block = Op.POP(Op.STATICCALL(Op.GAS, address, 0, optimal_input_length, 0, 0)) benchmark_test( - pre=pre, - post={}, code_generator=JumpLoopGenerator( setup=Op.CODECOPY(0, 0, optimal_input_length), attack_block=attack_block ), @@ -736,10 +702,7 @@ def create_modexp_test_cases() -> list[ParameterSet]: ) def test_worst_modexp( benchmark_test: BenchmarkTestFiller, - pre: Alloc, - fork: Fork, mod_exp_input: ModExpInput, - gas_benchmark_value: int, ) -> None: """ Test running a block with as many calls to the MODEXP (5) precompile as @@ -748,16 +711,12 @@ def test_worst_modexp( attack_block = Op.POP( Op.STATICCALL(Op.GAS, 0x5, Op.PUSH0, Op.CALLDATASIZE, Op.PUSH0, Op.PUSH0) ) - - tx = JumpLoopGenerator( - setup=Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE), attack_block=attack_block - ).generate_transaction(pre, gas_benchmark_value, fork) - tx.data = Bytes(bytes(mod_exp_input).rstrip(b"\x00")) - benchmark_test( - pre=pre, - post={}, - tx=tx, + code_generator=JumpLoopGenerator( + setup=Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE), + attack_block=attack_block, + tx_kwargs={"data": bytes(mod_exp_input).rstrip(b"\x00")}, + ), ) @@ -1187,7 +1146,6 @@ def test_worst_modexp( ) def test_worst_precompile_fixed_cost( benchmark_test: BenchmarkTestFiller, - pre: Alloc, fork: Fork, precompile_address: Address, parameters: list[str] | list[BytesConcatenation] | list[bytes], @@ -1226,8 +1184,6 @@ def test_worst_precompile_fixed_cost( ) benchmark_test( - pre=pre, - post={}, code_generator=JumpLoopGenerator(setup=setup, attack_block=attack_block), ) @@ -1242,24 +1198,15 @@ def test_worst_jumps( sender=pre.fund_eoa(), ) - benchmark_test( - pre=pre, - post={}, - tx=tx, - ) + benchmark_test(tx=tx) def test_worst_jumpi_fallthrough( benchmark_test: BenchmarkTestFiller, - pre: Alloc, ) -> None: """Test running a JUMPI-intensive contract with fallthrough.""" benchmark_test( - pre=pre, - post={}, - code_generator=JumpLoopGenerator( - setup=Bytecode(), attack_block=Op.JUMPI(Op.PUSH0, Op.PUSH0) - ), + code_generator=JumpLoopGenerator(attack_block=Op.JUMPI(Op.PUSH0, Op.PUSH0)), ) @@ -1273,23 +1220,14 @@ def test_worst_jumpis( sender=pre.fund_eoa(), ) - benchmark_test( - pre=pre, - post={}, - tx=tx, - ) + benchmark_test(tx=tx) def test_worst_jumpdests( benchmark_test: BenchmarkTestFiller, - pre: Alloc, ) -> None: """Test running a JUMPDEST-intensive contract.""" - benchmark_test( - pre=pre, - post={}, - code_generator=JumpLoopGenerator(attack_block=Op.JUMPDEST), - ) + benchmark_test(code_generator=JumpLoopGenerator(attack_block=Op.JUMPDEST)) DEFAULT_BINOP_ARGS = ( @@ -1442,11 +1380,8 @@ def test_worst_jumpdests( ) def test_worst_binop_simple( benchmark_test: BenchmarkTestFiller, - pre: Alloc, opcode: Op, - fork: Fork, opcode_args: tuple[int, int], - gas_benchmark_value: int, ) -> None: """ Test running a block with as many binary instructions (takes two args, @@ -1458,22 +1393,19 @@ def test_worst_binop_simple( setup = Op.CALLDATALOAD(0) + Op.CALLDATALOAD(32) + Op.DUP2 + Op.DUP2 attack_block = Op.DUP2 + opcode cleanup = Op.POP + Op.POP + Op.DUP2 + Op.DUP2 - tx = JumpLoopGenerator( - setup=setup, attack_block=attack_block, cleanup=cleanup - ).generate_transaction(pre, gas_benchmark_value, fork) - tx.data = Bytes(tx_data) - benchmark_test( - pre=pre, - post={}, - tx=tx, + code_generator=JumpLoopGenerator( + setup=setup, + attack_block=attack_block, + cleanup=cleanup, + tx_kwargs={"data": tx_data}, + ), ) @pytest.mark.parametrize("opcode", [Op.ISZERO, Op.NOT]) def test_worst_unop( benchmark_test: BenchmarkTestFiller, - pre: Alloc, opcode: Op, ) -> None: """ @@ -1481,8 +1413,6 @@ def test_worst_unop( produces one value) as possible. """ benchmark_test( - pre=pre, - post={}, code_generator=JumpLoopGenerator(setup=Op.PUSH0, attack_block=opcode), ) @@ -1494,11 +1424,8 @@ def test_worst_unop( @pytest.mark.parametrize("val_mut", [True, False]) def test_worst_tload( benchmark_test: BenchmarkTestFiller, - fork: Fork, - pre: Alloc, key_mut: bool, val_mut: bool, - gas_benchmark_value: int, ) -> None: """Test running a block with as many TLOAD calls as possible.""" start_key = 41 @@ -1519,16 +1446,17 @@ def test_worst_tload( attack_block = Op.POP(Op.TLOAD(Op.CALLVALUE)) cleanup = code_key_mut + code_val_mut - - tx = JumpLoopGenerator( - setup=setup, attack_block=attack_block, cleanup=cleanup - ).generate_transaction(pre, gas_benchmark_value, fork) - tx.value = HexNumber(start_key if not key_mut and val_mut else 0) + tx_value = start_key if not key_mut and val_mut else 0 benchmark_test( - pre=pre, - post={}, - tx=tx, + code_generator=JumpLoopGenerator( + setup=setup, + attack_block=attack_block, + cleanup=cleanup, + tx_kwargs={ + "value": tx_value, + }, + ), ) @@ -1536,7 +1464,6 @@ def test_worst_tload( @pytest.mark.parametrize("dense_val_mut", [True, False]) def test_worst_tstore( benchmark_test: BenchmarkTestFiller, - pre: Alloc, key_mut: bool, dense_val_mut: bool, ) -> None: @@ -1554,8 +1481,6 @@ def test_worst_tstore( cleanup = Op.POP + Op.GAS if key_mut else Bytecode() benchmark_test( - pre=pre, - post={}, code_generator=JumpLoopGenerator(setup=setup, attack_block=attack_block, cleanup=cleanup), ) @@ -1639,11 +1564,7 @@ def select_shift_amount(shift_fn: Any, v: Any) -> Any: sender=pre.fund_eoa(), ) - benchmark_test( - pre=pre, - post={}, - tx=tx, - ) + benchmark_test(tx=tx) @pytest.mark.parametrize( @@ -1658,31 +1579,24 @@ def select_shift_amount(shift_fn: Any, v: Any) -> Any: def test_worst_blobhash( fork: Fork, benchmark_test: BenchmarkTestFiller, - pre: Alloc, blob_index: int, blobs_present: bool, - gas_benchmark_value: int, ) -> None: """Test running a block with as many BLOBHASH instructions as possible.""" - tx = ExtCallGenerator( - setup=Bytecode(), attack_block=Op.BLOBHASH(blob_index) - ).generate_transaction(pre, gas_benchmark_value, fork) - + tx_kwargs: Dict[str, Any] = {} if blobs_present > 0: - tx.ty = HexNumber(TransactionType.BLOB_TRANSACTION) - tx.max_fee_per_blob_gas = HexNumber(fork.min_base_fee_per_blob_gas()) - tx.max_fee_per_gas = HexNumber(1000) - tx.max_priority_fee_per_gas = HexNumber(0) - tx.access_list = [] - tx.blob_versioned_hashes = add_kzg_version( + tx_kwargs["ty"] = TransactionType.BLOB_TRANSACTION + tx_kwargs["max_fee_per_blob_gas"] = fork.min_base_fee_per_blob_gas() + tx_kwargs["blob_versioned_hashes"] = add_kzg_version( [i.to_bytes() * 32 for i in range(blobs_present)], BlobsSpec.BLOB_COMMITMENT_VERSION_KZG, ) benchmark_test( - pre=pre, - post={}, - tx=tx, + code_generator=ExtCallGenerator( + attack_block=Op.BLOBHASH(blob_index), + tx_kwargs=tx_kwargs, + ), ) @@ -1690,11 +1604,8 @@ def test_worst_blobhash( @pytest.mark.parametrize("op", [Op.MOD, Op.SMOD]) def test_worst_mod( benchmark_test: BenchmarkTestFiller, - pre: Alloc, - fork: Fork, mod_bits: int, op: Op, - gas_benchmark_value: int, ) -> None: """ Test running a block with as many MOD instructions with arguments of the @@ -1793,17 +1704,13 @@ def test_worst_mod( Op.CALLDATALOAD(0) + sum(make_dup(len(numerators) - i) + op for i in indexes) + Op.POP ) - tx = JumpLoopGenerator(setup=setup, attack_block=attack_block).generate_transaction( - pre, gas_benchmark_value, fork - ) - input_value = initial_mod if not should_negate else neg(initial_mod) - tx.data = Bytes(input_value.to_bytes(32, byteorder="big")) - benchmark_test( - pre=pre, - post={}, - tx=tx, + code_generator=JumpLoopGenerator( + setup=setup, + attack_block=attack_block, + tx_kwargs={"data": input_value.to_bytes(32, byteorder="big")}, + ), ) @@ -1813,7 +1720,6 @@ def test_worst_mod( @pytest.mark.parametrize("big_memory_expansion", [True, False]) def test_worst_memory_access( benchmark_test: BenchmarkTestFiller, - pre: Alloc, opcode: Op, offset: int, offset_initialized: bool, @@ -1830,8 +1736,6 @@ def test_worst_memory_access( attack_block = Op.POP(Op.MLOAD(Op.DUP1)) if opcode == Op.MLOAD else opcode(Op.DUP2, Op.DUP2) benchmark_test( - pre=pre, - post={}, code_generator=JumpLoopGenerator(setup=setup, attack_block=attack_block), ) @@ -1938,21 +1842,14 @@ def test_worst_modarith( sender=pre.fund_eoa(), ) - benchmark_test( - pre=pre, - post={}, - tx=tx, - ) + benchmark_test(tx=tx) def test_empty_block( benchmark_test: BenchmarkTestFiller, - pre: Alloc, ) -> None: """Test running an empty block as a baseline for fixed proving costs.""" benchmark_test( - pre=pre, - post={}, blocks=[Block(txs=[])], expected_benchmark_gas_used=0, ) @@ -1960,7 +1857,6 @@ def test_empty_block( def test_amortized_bn128_pairings( benchmark_test: BenchmarkTestFiller, - pre: Alloc, fork: Fork, gas_benchmark_value: int, ) -> None: @@ -2009,15 +1905,12 @@ def test_amortized_bn128_pairings( setup = Op.CALLDATACOPY(size=Op.CALLDATASIZE) attack_block = Op.POP(Op.STATICCALL(Op.GAS, 0x08, 0, Op.CALLDATASIZE, 0, 0)) - tx = JumpLoopGenerator(setup=setup, attack_block=attack_block).generate_transaction( - pre, gas_benchmark_value, fork - ) - tx.data = _generate_bn128_pairs(optimal_per_call_num_pairings, 42) - benchmark_test( - pre=pre, - post={}, - tx=tx, + code_generator=JumpLoopGenerator( + setup=setup, + attack_block=attack_block, + tx_kwargs={"data": _generate_bn128_pairs(optimal_per_call_num_pairings, 42)}, + ), ) @@ -2061,20 +1954,15 @@ def _generate_bn128_pairs(n: int, seed: int = 0) -> Bytes: ) def test_worst_calldataload( benchmark_test: BenchmarkTestFiller, - pre: Alloc, calldata: bytes, - gas_benchmark_value: int, - fork: Fork, ) -> None: """Test running a block with as many CALLDATALOAD as possible.""" - tx = JumpLoopGenerator(setup=Op.PUSH0, attack_block=Op.CALLDATALOAD).generate_transaction( - pre, gas_benchmark_value, fork - ) - tx.data = Bytes(calldata) benchmark_test( - pre=pre, - post={}, - tx=tx, + code_generator=JumpLoopGenerator( + setup=Op.PUSH0, + attack_block=Op.CALLDATALOAD, + tx_kwargs={"data": calldata}, + ), ) @@ -2101,13 +1989,10 @@ def test_worst_calldataload( ) def test_worst_swap( benchmark_test: BenchmarkTestFiller, - pre: Alloc, opcode: Opcode, ) -> None: """Test running a block with as many SWAP as possible.""" benchmark_test( - pre=pre, - post={}, code_generator=JumpLoopGenerator( attack_block=opcode, setup=Op.PUSH0 * opcode.min_stack_height ), @@ -2151,9 +2036,7 @@ def test_worst_dup( attack_block = Op.POP(Op.STATICCALL(Op.GAS, target_contract_address, 0, 0, 0, 0)) benchmark_test( - pre=pre, - post={}, - code_generator=JumpLoopGenerator(setup=Bytecode(), attack_block=attack_block), + code_generator=JumpLoopGenerator(attack_block=attack_block), ) @@ -2197,15 +2080,12 @@ def test_worst_dup( ) def test_worst_push( benchmark_test: BenchmarkTestFiller, - pre: Alloc, opcode: Op, ) -> None: """Test running a block with as many PUSH as possible.""" benchmark_test( - pre=pre, - post={}, code_generator=ExtCallGenerator( - setup=Bytecode(), attack_block=opcode[1] if opcode.has_data_portion() else opcode + attack_block=opcode[1] if opcode.has_data_portion() else opcode ), ) @@ -2256,23 +2136,15 @@ def test_worst_return_revert( attack_block = Op.POP(Op.STATICCALL(address=target_contract_address)) benchmark_test( - pre=pre, - post={}, - code_generator=JumpLoopGenerator(setup=Bytecode(), attack_block=attack_block), + code_generator=JumpLoopGenerator(attack_block=attack_block), ) @pytest.mark.valid_from("Osaka") -def test_worst_clz_same_input( - benchmark_test: BenchmarkTestFiller, - pre: Alloc, -) -> None: +def test_worst_clz_same_input(benchmark_test: BenchmarkTestFiller) -> None: """Test running a block with as many CLZ with same input as possible.""" magic_value = 248 # CLZ(248) = 248 - benchmark_test( - pre=pre, - post={}, code_generator=JumpLoopGenerator(setup=Op.PUSH1(magic_value), attack_block=Op.CLZ), ) @@ -2311,8 +2183,4 @@ def test_worst_clz_diff_input( sender=pre.fund_eoa(), ) - benchmark_test( - pre=pre, - post={}, - tx=tx, - ) + benchmark_test(tx=tx) diff --git a/tests/benchmark/test_worst_memory.py b/tests/benchmark/test_worst_memory.py index 116f3a9551f..70667521e2e 100755 --- a/tests/benchmark/test_worst_memory.py +++ b/tests/benchmark/test_worst_memory.py @@ -96,7 +96,7 @@ def test_worst_calldatacopy( ) code_address = JumpLoopGenerator(setup=setup, attack_block=attack_block).deploy_contracts( - pre, fork + pre=pre, fork=fork ) tx_target = code_address @@ -115,7 +115,7 @@ def test_worst_calldatacopy( ) tx_target = JumpLoopGenerator(setup=setup, attack_block=attack_block).deploy_contracts( - pre, fork + pre=pre, fork=fork ) tx = Transaction( @@ -125,11 +125,7 @@ def test_worst_calldatacopy( sender=pre.fund_eoa(), ) - benchmark_test( - pre=pre, - post={}, - tx=tx, - ) + benchmark_test(tx=tx) @pytest.mark.parametrize( @@ -166,7 +162,7 @@ def test_worst_codecopy( attack_block = Op.CODECOPY(src_dst, src_dst, Op.DUP1) # DUP1 copies size. code = JumpLoopGenerator(setup=setup, attack_block=attack_block).generate_repeated_code( - repeated_code=attack_block, setup=setup, cleanup=Bytecode(), fork=fork + repeated_code=attack_block, setup=setup, fork=fork ) # The code generated above is not guaranteed to be of max_code_size, so @@ -184,11 +180,7 @@ def test_worst_codecopy( sender=pre.fund_eoa(), ) - benchmark_test( - pre=pre, - post={}, - tx=tx, - ) + benchmark_test(tx=tx) @pytest.mark.parametrize( @@ -249,8 +241,6 @@ def test_worst_returndatacopy( # generate fresh returndata to continue calling RETURNDATACOPY. benchmark_test( - pre=pre, - post={}, code_generator=JumpLoopGenerator( setup=returndata_gen, attack_block=attack_block, cleanup=returndata_gen ), @@ -275,7 +265,6 @@ def test_worst_returndatacopy( ) def test_worst_mcopy( benchmark_test: BenchmarkTestFiller, - pre: Alloc, size: int, fixed_src_dst: bool, ) -> None: @@ -289,8 +278,6 @@ def test_worst_mcopy( else Bytecode() ) benchmark_test( - pre=pre, - post={}, code_generator=JumpLoopGenerator( setup=mem_touch, attack_block=attack_block, cleanup=mem_touch ), diff --git a/tests/benchmark/test_worst_opcode.py b/tests/benchmark/test_worst_opcode.py index 8d4a87a3f90..f632d56bc82 100755 --- a/tests/benchmark/test_worst_opcode.py +++ b/tests/benchmark/test_worst_opcode.py @@ -6,7 +6,6 @@ from ethereum_test_benchmark.benchmark_code_generator import JumpLoopGenerator from ethereum_test_tools import ( - Alloc, BenchmarkTestFiller, Bytecode, ) @@ -38,7 +37,6 @@ @pytest.mark.parametrize("fixed_offset", [True, False]) def test_worst_log_opcodes( benchmark_test: BenchmarkTestFiller, - pre: Alloc, opcode: Opcode, zeros_topic: bool, size: int, @@ -68,7 +66,5 @@ def test_worst_log_opcodes( attack_block = Op.DUP1 * topic_count + size_op + offset + opcode benchmark_test( - pre=pre, - post={}, code_generator=JumpLoopGenerator(setup=setup, attack_block=attack_block), ) diff --git a/tests/benchmark/test_worst_stateful_opcodes.py b/tests/benchmark/test_worst_stateful_opcodes.py index 002a2b9833b..10f29289f34 100755 --- a/tests/benchmark/test_worst_stateful_opcodes.py +++ b/tests/benchmark/test_worst_stateful_opcodes.py @@ -109,7 +109,6 @@ def test_worst_address_state_cold( blocks.append(Block(txs=[op_tx])) benchmark_test( - pre=pre, post=post, blocks=blocks, ) @@ -156,7 +155,6 @@ def test_worst_address_state_warm( setup = Op.MSTORE(0, target_addr) attack_block = Op.POP(opcode(address=Op.MLOAD(0))) benchmark_test( - pre=pre, post=post, code_generator=JumpLoopGenerator(setup=setup, attack_block=attack_block), ) @@ -353,8 +351,6 @@ def test_worst_storage_access_cold( blocks.append(Block(txs=[op_tx])) benchmark_test( - pre=pre, - post={}, blocks=blocks, expected_benchmark_gas_used=( total_gas_used if tx_result != TransactionResult.OUT_OF_GAS else gas_benchmark_value @@ -428,11 +424,7 @@ def test_worst_storage_access_warm( ) blocks.append(Block(txs=[op_tx])) - benchmark_test( - pre=pre, - post={}, - blocks=blocks, - ) + benchmark_test(blocks=blocks) def test_worst_blockhash( @@ -449,10 +441,8 @@ def test_worst_blockhash( # Create 256 dummy blocks to fill the blockhash window. blocks = [Block()] * 256 - code = ExtCallGenerator(setup=Bytecode(), attack_block=Op.BLOCKHASH(1)).generate_repeated_code( + code = ExtCallGenerator(attack_block=Op.BLOCKHASH(1)).generate_repeated_code( repeated_code=Op.BLOCKHASH(1), - setup=Bytecode(), - cleanup=Bytecode(), fork=fork, ) @@ -473,22 +463,22 @@ def test_worst_blockhash( blocks.append(Block(txs=txs)) benchmark_test( - pre=pre, - post={}, blocks=blocks, expected_benchmark_gas_used=gas_benchmark_value, ) +@pytest.mark.parametrize("contract_balance", [0, 1]) def test_worst_selfbalance( benchmark_test: BenchmarkTestFiller, - pre: Alloc, + contract_balance: int, ) -> None: """Test running a block with as many SELFBALANCE opcodes as possible.""" benchmark_test( - pre=pre, - post={}, - code_generator=ExtCallGenerator(setup=Bytecode(), attack_block=Op.SELFBALANCE), + code_generator=ExtCallGenerator( + attack_block=Op.SELFBALANCE, + contract_balance=contract_balance, + ), ) @@ -525,11 +515,7 @@ def test_worst_extcodecopy_warm( sender=pre.fund_eoa(), ) - benchmark_test( - pre=pre, - post={}, - tx=tx, - ) + benchmark_test(tx=tx) @pytest.mark.parametrize("value_bearing", [True, False]) @@ -666,7 +652,6 @@ def test_worst_selfdestruct_existing( deployed_contract_addresses.append(deployed_contract_address) benchmark_test( - pre=pre, post=post, blocks=[ Block(txs=[contracts_deployment_tx]), From c3fb57cbaa06a3c27e7deb6b61d28cd408202b54 Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Mon, 13 Oct 2025 14:55:18 +0800 Subject: [PATCH 16/18] refactor(benchmark): Improve max_iterations calculation --- .../benchmark_code_generator.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/ethereum_test_benchmark/benchmark_code_generator.py b/src/ethereum_test_benchmark/benchmark_code_generator.py index 7061acdd0f3..e026cdd2de0 100644 --- a/src/ethereum_test_benchmark/benchmark_code_generator.py +++ b/src/ethereum_test_benchmark/benchmark_code_generator.py @@ -46,9 +46,14 @@ def deploy_contracts(self, *, pre: Alloc, fork: Fork) -> Address: # but not loop (e.g. PUSH) # 2. The loop contract that calls the target contract in a loop - max_iterations = min( - fork.max_stack_height(), fork.max_code_size() // len(self.attack_block) - ) + pushed_stack_items = self.attack_block.pushed_stack_items + popped_stack_items = self.attack_block.popped_stack_items + stack_delta = pushed_stack_items - popped_stack_items + + max_iterations = fork.max_code_size() // len(self.attack_block) + + if stack_delta > 0: + max_iterations = min(fork.max_stack_height() // stack_delta, max_iterations) # Deploy target contract that contains the actual attack block self._target_contract_address = pre.deploy_contract( From dfbce46b5ff50403f1c62c4c344f46e9cf281ede Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Mon, 13 Oct 2025 16:42:55 +0800 Subject: [PATCH 17/18] feat(benchmark): add setup_blocks and update tests --- src/ethereum_test_specs/benchmark.py | 7 ++++++ tests/benchmark/test_worst_compute.py | 4 +-- .../benchmark/test_worst_stateful_opcodes.py | 25 ++----------------- 3 files changed, 11 insertions(+), 25 deletions(-) diff --git a/src/ethereum_test_specs/benchmark.py b/src/ethereum_test_specs/benchmark.py index 2397a209eaa..1e2e02ef5f3 100644 --- a/src/ethereum_test_specs/benchmark.py +++ b/src/ethereum_test_specs/benchmark.py @@ -107,6 +107,7 @@ class BenchmarkTest(BaseTest): pre: Alloc = Field(default_factory=Alloc) post: Alloc = Field(default_factory=Alloc) tx: Transaction | None = None + setup_blocks: List[Block] | None = None blocks: List[Block] | None = None block_exception: ( List[TransactionException | BlockException] | TransactionException | BlockException | None @@ -234,6 +235,12 @@ def generate_blockchain_test(self, fork: Fork) -> BlockchainTest: f"Exactly one must be set, but got {len(set_props)}: {', '.join(set_props)}" ) + if self.setup_blocks is not None: + if self.blocks is not None: + self.blocks.insert(0, *self.setup_blocks) + else: + self.blocks = self.setup_blocks + if self.code_generator is not None: generated_blocks = self.generate_blocks_from_code_generator(fork) return BlockchainTest.from_test( diff --git a/tests/benchmark/test_worst_compute.py b/tests/benchmark/test_worst_compute.py index c1610c027fd..40e0eff2f15 100755 --- a/tests/benchmark/test_worst_compute.py +++ b/tests/benchmark/test_worst_compute.py @@ -217,9 +217,9 @@ def test_worst_msize( """ benchmark_test( code_generator=ExtCallGenerator( - setup=Op.MLOAD(Op.CALLVALUE) + Op.POP, + setup=Op.MLOAD(Op.SELFBALANCE) + Op.POP, attack_block=Op.MSIZE, - tx_kwargs={"value": mem_size}, + contract_balance=mem_size, ), ) diff --git a/tests/benchmark/test_worst_stateful_opcodes.py b/tests/benchmark/test_worst_stateful_opcodes.py index 10f29289f34..845fb1cad9b 100755 --- a/tests/benchmark/test_worst_stateful_opcodes.py +++ b/tests/benchmark/test_worst_stateful_opcodes.py @@ -7,7 +7,6 @@ import pytest -from ethereum_test_base_types import HexNumber from ethereum_test_benchmark.benchmark_code_generator import ExtCallGenerator, JumpLoopGenerator from ethereum_test_forks import Fork from ethereum_test_specs import StateTestFiller @@ -441,29 +440,9 @@ def test_worst_blockhash( # Create 256 dummy blocks to fill the blockhash window. blocks = [Block()] * 256 - code = ExtCallGenerator(attack_block=Op.BLOCKHASH(1)).generate_repeated_code( - repeated_code=Op.BLOCKHASH(1), - fork=fork, - ) - - iteration_count = math.ceil(gas_benchmark_value / tx_gas_limit_cap) - code_address = pre.deploy_contract(code=code) - - gas_remaining = gas_benchmark_value - txs = [] - for _ in range(iteration_count): - tx_gas_limit = min(tx_gas_limit_cap, gas_remaining) - gas_remaining -= tx_gas_limit - tx = Transaction( - to=code_address, - gas_limit=HexNumber(tx_gas_limit), - sender=pre.fund_eoa(), - ) - txs.append(tx) - blocks.append(Block(txs=txs)) - benchmark_test( - blocks=blocks, + setup_blocks=blocks, + code_generator=ExtCallGenerator(attack_block=Op.BLOCKHASH(1)), expected_benchmark_gas_used=gas_benchmark_value, ) From e1303cc74bef67ee563cd74dc14307352aeabac8 Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Mon, 13 Oct 2025 20:54:40 +0000 Subject: [PATCH 18/18] fix(specs): Make sure setup blocks are always used --- src/ethereum_test_specs/benchmark.py | 47 +++++++++++----------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/src/ethereum_test_specs/benchmark.py b/src/ethereum_test_specs/benchmark.py index 1e2e02ef5f3..ff9f94a2c59 100644 --- a/src/ethereum_test_specs/benchmark.py +++ b/src/ethereum_test_specs/benchmark.py @@ -107,7 +107,7 @@ class BenchmarkTest(BaseTest): pre: Alloc = Field(default_factory=Alloc) post: Alloc = Field(default_factory=Alloc) tx: Transaction | None = None - setup_blocks: List[Block] | None = None + setup_blocks: List[Block] = Field(default_factory=list) blocks: List[Block] | None = None block_exception: ( List[TransactionException | BlockException] | TransactionException | BlockException | None @@ -235,45 +235,34 @@ def generate_blockchain_test(self, fork: Fork) -> BlockchainTest: f"Exactly one must be set, but got {len(set_props)}: {', '.join(set_props)}" ) - if self.setup_blocks is not None: - if self.blocks is not None: - self.blocks.insert(0, *self.setup_blocks) - else: - self.blocks = self.setup_blocks + blocks: List[Block] = self.setup_blocks if self.code_generator is not None: generated_blocks = self.generate_blocks_from_code_generator(fork) - return BlockchainTest.from_test( - base_test=self, - genesis_environment=self.env, - pre=self.pre, - post=self.post, - blocks=generated_blocks, - ) + blocks += generated_blocks + elif self.blocks is not None: - return BlockchainTest.from_test( - base_test=self, - genesis_environment=self.env, - pre=self.pre, - post=self.post, - blocks=self.blocks, - ) + blocks += self.blocks + elif self.tx is not None: gas_limit = fork.transaction_gas_limit_cap() or self.gas_benchmark_value transactions = self.split_transaction(self.tx, gas_limit) - blocks = [Block(txs=transactions)] + blocks.append(Block(txs=transactions)) - return BlockchainTest.from_test( - base_test=self, - pre=self.pre, - post=self.post, - blocks=blocks, - genesis_environment=self.env, - ) else: - raise ValueError("Cannot create BlockchainTest without transactions or blocks") + raise ValueError( + "Cannot create BlockchainTest without a code generator, transactions, or blocks" + ) + + return BlockchainTest.from_test( + base_test=self, + genesis_environment=self.env, + pre=self.pre, + post=self.post, + blocks=blocks, + ) def generate( self,