From be591ea8734a60742204fbdee25ced3a8a0943ab Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Wed, 17 Jun 2026 16:56:04 +0800 Subject: [PATCH 1/7] chore: remove account access benchmark --- .../stateful/bloatnet/test_single_opcode.py | 215 ------------------ 1 file changed, 215 deletions(-) diff --git a/tests/benchmark/stateful/bloatnet/test_single_opcode.py b/tests/benchmark/stateful/bloatnet/test_single_opcode.py index eb5cb4c25a..ce32744374 100644 --- a/tests/benchmark/stateful/bloatnet/test_single_opcode.py +++ b/tests/benchmark/stateful/bloatnet/test_single_opcode.py @@ -7,7 +7,6 @@ to benchmark specific state-handling bottlenecks. """ -from enum import Enum, auto from functools import partial from typing import Any, Callable, Generator, List @@ -25,18 +24,15 @@ Block, BlockAccessListExpectation, Bytecode, - CreatePreimageLayout, Fork, Hash, IteratingBytecode, JumpLoopGenerator, Op, - SequentialAddressLayout, Storage, TestPhaseManager, Transaction, While, - keccak256, ) from execution_testing.base_types.base_types import Number @@ -1541,214 +1537,3 @@ def test_storage_sload_same_key_benchmark( contract_storage=contract_storage, ), ) - - -def account_access_params() -> list: - """Generate (opcode, value_sent, account_mode) triples.""" - params = [] - - for mode in AccountMode: - for op in [Op.CALL, Op.CALLCODE]: - params.append(pytest.param(op, 0, mode)) - params.append(pytest.param(op, 1, mode)) - - for op in [Op.BALANCE, Op.STATICCALL, Op.DELEGATECALL]: - params.append(pytest.param(op, 0, mode)) - - for op in [Op.EXTCODECOPY, Op.EXTCODESIZE, Op.EXTCODEHASH]: - for mode in [ - AccountMode.EXISTING_CONTRACT, - AccountMode.NON_EXISTING_ACCOUNT, - ]: - params.append(pytest.param(op, 0, mode)) - - return params - - -class AccountMode(Enum): - """Target Account Mode.""" - - EXISTING_CONTRACT = auto() - EXISTING_EOA = auto() - NON_EXISTING_ACCOUNT = auto() - - -@pytest.mark.repricing -@pytest.mark.parametrize("cache_strategy", [CacheStrategy.NO_CACHE]) -@pytest.mark.parametrize( - "opcode,value_sent,account_mode", account_access_params() -) -def test_account_access( - benchmark_test: BenchmarkTestFiller, - pre: Alloc, - fork: Fork, - opcode: Op, - value_sent: int, - gas_benchmark_value: int, - fixed_opcode_count: int | None, - account_mode: AccountMode, - cache_strategy: CacheStrategy, -) -> None: - """Benchmark account access with caching strategies.""" - address_retriever: Bytecode - # Read start_iteration from calldata so that when transactions are - # split across gas limits, each transaction continues from where - # the previous one left off instead of re-targeting the same accounts. - calldataload_start = Op.CALLDATALOAD(0) - if account_mode == AccountMode.EXISTING_CONTRACT: - # Use Bittrex Controller as target. Created 1586350 contracts, - # which cannot selfdestruct, so guaranteed to be on-chain. - # This is safe for a gas benchmark up to 300M. (300_000_000 / 2000) - # (2000 is the min cost to target a cold address) - target_address = Address(0xA3C1E324CA1CE40DB73ED6026C4A177F099B5770) - address_retriever = CreatePreimageLayout( - sender_address=target_address, - nonce=Op.ADD(1, calldataload_start), - ) - increment_op = address_retriever.increment_nonce_op() - elif account_mode == AccountMode.EXISTING_EOA: - # Spamoor EOA creator (https://github.com/CPerezz/spamoor/pull/12) - # created these accounts on bloatnet with these values (are also the - # defaults of SequentialAddressLayout) - address_retriever = SequentialAddressLayout( - starting_address=Op.ADD(0x1000, calldataload_start), - increment=1, - ) - increment_op = address_retriever.increment_address_op() - else: - address_retriever = SequentialAddressLayout( - starting_address=Op.ADD(keccak256(b"random"), calldataload_start), - increment=1, - ) - increment_op = address_retriever.increment_address_op() - - setup_code: Bytecode = address_retriever - - cache_op = ( - Op.POP( - Op.BALANCE( - address=address_retriever.address_op(), - # Gas accounting - address_warm=False, - ) - ) - if cache_strategy == CacheStrategy.CACHE_TX - else Bytecode() - ) - - access_warm = cache_strategy == CacheStrategy.CACHE_TX - - if opcode == Op.EXTCODECOPY: - attack_call = opcode( - address=address_retriever.address_op(), - size=1024, - # Gas accounting - address_warm=access_warm, - ) - elif opcode in (Op.CALL, Op.CALLCODE): - attack_call = Op.POP( - opcode( - address=address_retriever.address_op(), - value=value_sent, - # Gas accounting - address_warm=access_warm, - value_transfer=value_sent > 0, - account_new=value_sent > 0 - and account_mode == AccountMode.NON_EXISTING_ACCOUNT, - ) - ) - elif opcode in (Op.STATICCALL, Op.DELEGATECALL): - attack_call = Op.POP( - opcode( - address=address_retriever.address_op(), - # Gas accounting - address_warm=access_warm, - ) - ) - else: - # BALANCE, EXTCODESIZE, EXTCODEHASH - attack_call = Op.POP( - opcode( - address=address_retriever.address_op(), - # Gas accounting - address_warm=access_warm, - ) - ) - - loop_code = While( - body=cache_op + attack_call + increment_op, - condition=Op.GT(Op.GAS, 0x9000) if value_sent > 0 else None, - ) - - attack_code = IteratingBytecode( - setup=setup_code, - iterating=loop_code, - # Since the target contract is guaranteed to have a STOP as the first - # instruction, we can use a STOP as the iterating subcall code. - iterating_subcall=Op.STOP, - ) - - # Calldata generator for each transaction of the iterating bytecode. - # Start from 1 to skip the Bittrex Controller's nonce=1 contract - # which has a non-payable fallback that reverts when receiving value. - calldata_offset = 1 if account_mode == AccountMode.EXISTING_CONTRACT else 0 - - def calldata(iteration_count: int, start_iteration: int) -> bytes: - del iteration_count - return Hash(start_iteration + calldata_offset) - - attack_address = pre.deploy_contract(code=attack_code, balance=10**21) - - post: dict = {} - cache_txs = [] - - with TestPhaseManager.execution(): - attack_sender = pre.fund_eoa() - if fixed_opcode_count is not None: - attack_txs = list( - attack_code.transactions_by_total_iteration_count( - fork=fork, - total_iterations=int(fixed_opcode_count * 1000), - sender=attack_sender, - to=attack_address, - calldata=calldata, - ) - ) - else: - attack_txs = list( - attack_code.transactions_by_gas_limit( - fork=fork, - gas_limit=gas_benchmark_value, - sender=attack_sender, - to=attack_address, - calldata=calldata, - ) - ) - - if cache_strategy == CacheStrategy.CACHE_PREVIOUS_BLOCK: - with TestPhaseManager.setup(): - cache_sender = pre.fund_eoa() - for tx in attack_txs: - cache_txs.append( - Transaction( - gas_limit=tx.gas_limit, - data=tx.data, - to=attack_address, - sender=cache_sender, - ) - ) - - blocks = ( - [Block(txs=attack_txs)] - if cache_strategy != CacheStrategy.CACHE_PREVIOUS_BLOCK - else [Block(txs=cache_txs), Block(txs=attack_txs)] - ) - - benchmark_test( - pre=pre, - post=post, - blocks=blocks, - target_opcode=opcode, - skip_gas_used_validation=True, - expected_receipt_status=1, - ) From 259dbff728fb6fb4903a92fd08d919370c674be0 Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Wed, 17 Jun 2026 16:58:20 +0800 Subject: [PATCH 2/7] feat: account creation helper function --- tests/benchmark/helper/__init__.py | 1 + tests/benchmark/helper/account_creator.py | 319 ++++++++++++++++++++++ tests/benchmark/stateful/helpers.py | 6 +- 3 files changed, 323 insertions(+), 3 deletions(-) create mode 100644 tests/benchmark/helper/__init__.py create mode 100644 tests/benchmark/helper/account_creator.py diff --git a/tests/benchmark/helper/__init__.py b/tests/benchmark/helper/__init__.py new file mode 100644 index 0000000000..f2cab960ab --- /dev/null +++ b/tests/benchmark/helper/__init__.py @@ -0,0 +1 @@ +"""Shared helpers reused across benchmark test suites.""" diff --git a/tests/benchmark/helper/account_creator.py b/tests/benchmark/helper/account_creator.py new file mode 100644 index 0000000000..c93cd94f7a --- /dev/null +++ b/tests/benchmark/helper/account_creator.py @@ -0,0 +1,319 @@ +"""Benchmark target accounts of various kinds for creation and location..""" + +from abc import ABC, abstractmethod +from collections.abc import Callable +from dataclasses import dataclass +from enum import Enum, auto +from functools import partial +from typing import ClassVar, Self + +from execution_testing import ( + DETERMINISTIC_FACTORY_ADDRESS, + Bytecode, + Create2PreimageLayout, + Hash, + Op, + SequentialAddressLayout, + keccak256, +) + +# Runtime code size of the jochemnet contract (EIP-170 limit). +JOCHEMNET_RUNTIME_SIZE = 0x6000 + + +class AccountMode(Enum): + """Benchmark target account variant.""" + + # Minimal contract: single STOP byte. + EXISTING_CONTRACT_MINIMAL = auto() + + # Max-size contract: byte-identical across copies. + EXISTING_CONTRACT_SAME = auto() + + # Max-size contract: ADDRESS-embedded, each copy unique. + EXISTING_CONTRACT_DIFF = auto() + + # Max-size contract: exercises JUMPDEST analysis. + EXISTING_CONTRACT_JUMPDEST = auto() + + # EOA with balance. + EXISTING_EOA = auto() + + # Empty account + NON_EXISTING_ACCOUNT = auto() + + +class ContractInitcode(Bytecode): + """Initcode for target contract receiver.""" + + @property + def runtime_size(self) -> int: + """Size in bytes of the deployed runtime.""" + raise NotImplementedError + + @property + def runtime_code(self) -> Bytecode: + """Runtime executed when the deployed contract is called.""" + raise NotImplementedError + + +class MinimalContractInitcode(ContractInitcode): + """Initcode whose deployed runtime is a single STOP opcode.""" + + def __new__(cls) -> Self: + """Assemble the initcode.""" + return super().__new__(cls, Op.RETURN(Op.PUSH1(0), Op.PUSH1(1))) + + @property + def runtime_size(self) -> int: + """Size in bytes of the deployed runtime.""" + return len(Op.STOP) + + @property + def runtime_code(self) -> Bytecode: + """Runtime executed when the deployed contract is called.""" + return Op.STOP + + +class UniqueMaxContractInitcode(ContractInitcode): + """ + Initcode for a max code size JUMPDEST-filled runtime contract. + + offset size contents + ------ ---- -------------------------------- + 0x0000 1 STOP <- a call halts here + 0x0001 11 00 padding <- diff=True only + 0x000C 20 contract ADDRESS <- diff=True only + 0x0020 24544 JUMPDEST <- fills up to 0x6000 + + *diff* embeds ADDRESS (bytes 12-31), making each copy unique. + Without it, all copies are identical (JUMPDEST bytes 1-31) + """ + + def __new__(cls, *, diff: bool = False) -> Self: + """Assemble the initcode.""" + # Each MCOPY doubles the JUMPDEST-filled span up to MEM[0:0x8000]; + # the deployed runtime only uses MEM[0:0x6000]. + code = Op.MSTORE(0, bytes(Op.JUMPDEST * 32)) + for size in (1 << s for s in range(5, 15)): + code += Op.MCOPY(size, 0, size) + + if diff: + # Embeds ADDRESS in the runtime to make each copy unique + code += Op.MSTORE(0, Op.ADDRESS) + else: + # Without embedding, all copies are byte-identical; + code += Op.MSTORE8(0, 0) + code += Op.RETURN(0, JOCHEMNET_RUNTIME_SIZE) + return super().__new__(cls, code) + + @property + def runtime_size(self) -> int: + """Size in bytes of the deployed runtime.""" + return JOCHEMNET_RUNTIME_SIZE + + @property + def runtime_code(self) -> Bytecode: + """Runtime executed when the deployed contract is called.""" + return Op.STOP + + +class JochemnetPredeployContractInitcode(ContractInitcode): + """ + Initcode whose deployed runtime embeds its own contract ADDRESS. + + offset size contents + ------ ---- -------------------------------- + 0x0000 4 PUSH2 0x5FFF; JUMP <- entry + 0x0004 28 JUMPDEST padding + 0x0020 12 JUMPDEST padding + 0x002C 20 contract ADDRESS <- unique + 0x0040 24512 JUMPDEST <- 0x5FFF lands here + 0x6000 STOP + + Embedded ADDRESS makes the runtime unique per contract; initcode and + its CREATE2 hash are shared across all salts. + """ + + def __new__(cls) -> Self: + """Assemble the initcode.""" + max_code_size = JOCHEMNET_RUNTIME_SIZE + + # Each MCOPY doubles the JUMPDEST-filled span up to MEM[0:0x8000]; + # the deployed runtime only uses MEM[0:0x6000]. + code = Op.MSTORE(0, bytes(Op.JUMPDEST * 32)) + for size in (1 << s for s in range(5, 15)): + code += Op.MCOPY(size, 0, size) + + # Runtime entry: JUMP to final JUMPDEST, then STOP. + entry = Op.JUMP(max_code_size - 1) + entry += Op.JUMPDEST * (32 - len(entry)) # Padding + + code += Op.MSTORE(0, bytes(entry)) + + # Mask ADDRESS into a JUMPDEST template via OR: + # bytes 0..12 bytes 12..32 + # ----------- ------------ + # ADDRESS 00 .. 00 <20-byte address> + # addr_slot 5b .. 5b 00 .. 00 + # OR result 5b .. 5b <20-byte address> + addr_slot = Op.JUMPDEST * 12 + Op.STOP * 20 + code += Op.MSTORE(0x20, Op.OR(Op.ADDRESS, bytes(addr_slot))) + + code += Op.RETURN(0, max_code_size) + return super().__new__(cls, code) + + @property + def runtime_size(self) -> int: + """Size in bytes of the deployed runtime.""" + return JOCHEMNET_RUNTIME_SIZE + + @property + def runtime_code(self) -> Bytecode: + """Runtime executed when the deployed contract is called.""" + # Entry jumps to the final JUMPDEST, then halts. + return Op.JUMP(Op.PUSH2(JOCHEMNET_RUNTIME_SIZE - 1)) + Op.JUMPDEST + + +class AddressSource(ABC): + """ + Locates and iterates over target addresses. + + Provides a unified interface for layout initialization, + reading the current target, and advancing to the next one. + """ + + @property + @abstractmethod + def setup(self) -> Bytecode: + """Bytecode that initializes the in-memory address layout.""" + + @abstractmethod + def address_op(self) -> Bytecode: + """Bytecode that reads the current target address.""" + + @abstractmethod + def next_op(self) -> Bytecode: + """Bytecode that advances to the next target address.""" + + +class Create2AddressSource(AddressSource): + """Targets derived from a CREATE2 factory deployment.""" + + def __init__(self, *, init_code: bytes, index_op: Bytecode) -> None: + """Build the CREATE2 preimage layout for *init_code*.""" + self._layout = Create2PreimageLayout( + factory_address=DETERMINISTIC_FACTORY_ADDRESS, + salt=index_op, + init_code_hash=keccak256(init_code), + ) + + @property + def setup(self) -> Bytecode: + """Bytecode that initializes the in-memory address layout.""" + return self._layout + + def address_op(self) -> Bytecode: + """Bytecode that reads the current target address.""" + return self._layout.address_op() + + def next_op(self) -> Bytecode: + """Bytecode that advances to the next target address.""" + return self._layout.increment_salt_op() + + +class SequentialAddressSource(AddressSource): + """Targets at a contiguous address range starting from a base.""" + + def __init__(self, *, base_addr: Hash, index_op: Bytecode) -> None: + """Build a sequential layout starting at *base_addr*.""" + self._layout = SequentialAddressLayout( + starting_address=Op.ADD(base_addr, index_op), + increment=1, + ) + + @property + def setup(self) -> Bytecode: + """Bytecode that initializes the in-memory address layout.""" + return self._layout + + def address_op(self) -> Bytecode: + """Bytecode that reads the current target address.""" + return self._layout.address_op() + + def next_op(self) -> Bytecode: + """Bytecode that advances to the next target address.""" + return self._layout.increment_address_op() + + +@dataclass(frozen=True) +class AccountCreator: + """Account creation and location helper with address iteration.""" + + # Maps CREATE2 modes to initcode builders. + initcode_factories: ClassVar[ + dict[AccountMode, Callable[[], ContractInitcode]] + ] = { + AccountMode.EXISTING_CONTRACT_MINIMAL: MinimalContractInitcode, + AccountMode.EXISTING_CONTRACT_SAME: partial( + UniqueMaxContractInitcode, diff=False + ), + AccountMode.EXISTING_CONTRACT_DIFF: partial( + UniqueMaxContractInitcode, diff=True + ), + AccountMode.EXISTING_CONTRACT_JUMPDEST: ( + JochemnetPredeployContractInitcode + ), + } + + mode: AccountMode + + def __post_init__(self) -> None: + """Reject anything that is not a known `AccountMode`.""" + if not isinstance(self.mode, AccountMode): + raise ValueError(f"unknown account mode: {self.mode!r}") + + @property + def derives_address_via_create2(self) -> bool: + """Whether the target address is derived via CREATE2.""" + return self.mode in self.initcode_factories + + @property + def contract_initcode(self) -> ContractInitcode: + """Return the initcode generator that deploys this account.""" + if self.mode not in self.initcode_factories: + raise ValueError(f"{self.mode.name} is not a contract") + return self.initcode_factories[self.mode]() + + @property + def initcode(self) -> bytes: + """Return the CREATE2 initcode that deploys this account.""" + return bytes(self.contract_initcode) + + @property + def runtime_size(self) -> int: + """Return the deployed runtime size in bytes.""" + return self.contract_initcode.runtime_size + + @property + def runtime_code(self) -> Bytecode: + """Return the runtime executed when this account receives a call.""" + return self.contract_initcode.runtime_code + + def address_source(self, index_op: Bytecode) -> AddressSource: + """Return the source that yields successive target addresses.""" + if self.derives_address_via_create2: + return Create2AddressSource( + init_code=self.initcode, index_op=index_op + ) + match self.mode: + case AccountMode.EXISTING_EOA: + # Spamoor EOA creator starts created accounts at 0x1000. + # https://github.com/CPerezz/spamoor/pull/12 + base_addr = Hash(0x1000) + case AccountMode.NON_EXISTING_ACCOUNT: + # An address range that is never funded. + base_addr = keccak256(b"random") + case _: + raise ValueError(f"{self.mode.name} has no address source") + return SequentialAddressSource(base_addr=base_addr, index_op=index_op) diff --git a/tests/benchmark/stateful/helpers.py b/tests/benchmark/stateful/helpers.py index 033d532049..c6166a6e5e 100644 --- a/tests/benchmark/stateful/helpers.py +++ b/tests/benchmark/stateful/helpers.py @@ -1,6 +1,6 @@ """Shared constants and helpers for stateful benchmark tests.""" -from collections.abc import Callable +from collections.abc import Callable, Sequence from dataclasses import dataclass from enum import Enum from functools import partial @@ -125,8 +125,8 @@ def build_benchmark_txs( def build_cache_strategy_blocks( cache_strategy: CacheStrategy, - txs: list[Transaction], - cache_txs: list[Transaction], + txs: Sequence[Transaction], + cache_txs: Sequence[Transaction], ) -> list[Block]: """ Assemble benchmark blocks based on cache strategy. From 841fc939714fd3b34cb80f3b700a07760fd7eec5 Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Wed, 17 Jun 2026 16:58:37 +0800 Subject: [PATCH 3/7] feat: add account access benchmark --- .../stateful/bloatnet/test_account_query.py | 219 ++++++++++++++++-- 1 file changed, 206 insertions(+), 13 deletions(-) diff --git a/tests/benchmark/stateful/bloatnet/test_account_query.py b/tests/benchmark/stateful/bloatnet/test_account_query.py index bbcaa785d7..75be02af44 100644 --- a/tests/benchmark/stateful/bloatnet/test_account_query.py +++ b/tests/benchmark/stateful/bloatnet/test_account_query.py @@ -1,16 +1,4 @@ -""" -Benchmark operations that require querying the account state, either on the -current executing account or on a target account. - -Supported Opcodes: -- SELFBALANCE -- CODESIZE -- CODECOPY -- EXTCODESIZE -- EXTCODEHASH -- EXTCODECOPY -- BALANCE -""" +"""Benchmark operations that query the state of a target account.""" from typing import Any @@ -19,8 +7,24 @@ Account, Alloc, BenchmarkTestFiller, + Bytecode, + Fork, + Hash, + IteratingBytecode, JumpLoopGenerator, Op, + TestPhaseManager, + Transaction, + While, +) + +from tests.benchmark.helper.account_creator import ( + AccountCreator, + AccountMode, +) +from tests.benchmark.stateful.helpers import ( + CacheStrategy, + build_cache_strategy_blocks, ) @@ -106,3 +110,192 @@ def test_ext_account_query_warm( attack_block=Op.POP(opcode(address=Op.MLOAD(0))), ), ) + + +def account_access_params() -> list: + """Generate (opcode, value_sent, account_mode, overhead_baseline).""" + target_opcodes = [ + Op.BALANCE, + # CALL* + Op.CALL, + Op.CALLCODE, + Op.STATICCALL, + Op.DELEGATECALL, + # EXTCODE* + Op.EXTCODECOPY, + Op.EXTCODESIZE, + Op.EXTCODEHASH, + ] + value_bearing_opcodes = {Op.CALL, Op.CALLCODE} + params = [] + for mode in AccountMode: + for op in target_opcodes: + values = (0, 1) if op in value_bearing_opcodes else (0,) + for value_sent in values: + params.append(pytest.param(op, value_sent, mode, False)) + if AccountCreator(mode).derives_address_via_create2: + params.append(pytest.param(op, value_sent, mode, True)) + return params + + +@pytest.mark.repricing +@pytest.mark.parametrize("cache_strategy", CacheStrategy.NO_CACHE) +@pytest.mark.parametrize( + "opcode,value_sent,account_mode,overhead_baseline", account_access_params() +) +def test_account_access( + benchmark_test: BenchmarkTestFiller, + pre: Alloc, + fork: Fork, + opcode: Op, + value_sent: int, + gas_benchmark_value: int, + fixed_opcode_count: int | None, + account_mode: AccountMode, + overhead_baseline: bool, + cache_strategy: CacheStrategy, +) -> None: + """Benchmark account access with caching strategies.""" + address_source = AccountCreator(account_mode).address_source( + Op.CALLDATALOAD(0) + ) + increment_op = address_source.next_op() + + cache_op = ( + Op.POP( + Op.BALANCE( + address=address_source.address_op(), + # Gas accounting + address_warm=False, + ) + ) + if cache_strategy == CacheStrategy.CACHE_TX + else Bytecode() + ) + + access_warm = cache_strategy == CacheStrategy.CACHE_TX + + if opcode == Op.EXTCODECOPY: + attack_call = opcode( + address=address_source.address_op(), + size=1024, + # Gas accounting + address_warm=access_warm, + ) + elif opcode in (Op.CALL, Op.CALLCODE): + attack_call = Op.POP( + opcode( + address=address_source.address_op(), + value=value_sent, + # Gas accounting + address_warm=access_warm, + value_transfer=value_sent > 0, + account_new=( + value_sent > 0 + and account_mode == AccountMode.NON_EXISTING_ACCOUNT + ), + ) + ) + else: + # BALANCE, STATICCALL, DELEGATECALL, EXTCODESIZE, EXTCODEHASH + attack_call = Op.POP( + opcode( + address=address_source.address_op(), + # Gas accounting + address_warm=access_warm, + ) + ) + + loop_code = While( + body=cache_op + attack_call + increment_op, + condition=Op.GT(Op.GAS, 0x9000) if value_sent > 0 else None, + ) + + attack_code = IteratingBytecode( + setup=address_source.setup, + iterating=loop_code, + iterating_subcall=Op.STOP, + ) + + # Calldata generator for each transaction of the iterating bytecode. + def calldata(iteration_count: int, start_iteration: int) -> bytes: + del iteration_count + return Hash(start_iteration) + + run_code = attack_code + target_opcode = opcode + + if overhead_baseline: + keccak_op = Op.POP(address_source.address_op()) + if cache_strategy == CacheStrategy.CACHE_TX: + keccak_op = keccak_op * 2 + + run_code = IteratingBytecode( + setup=address_source.setup, + iterating=While(body=keccak_op + increment_op), + ) + target_opcode = Op.SHA3 + + total_iterations = None + if fixed_opcode_count is not None: + total_iterations = int(fixed_opcode_count * 1000) + elif overhead_baseline: + total_iterations = sum( + attack_code.tx_iterations_by_gas_limit( + fork=fork, + gas_limit=gas_benchmark_value, + calldata=calldata, + ) + ) + + attack_address = pre.deploy_contract(code=run_code, balance=10**21) + + post: dict = {} + cache_txs = [] + + with TestPhaseManager.execution(): + attack_sender = pre.fund_eoa() + if total_iterations is not None: + attack_txs = list( + run_code.transactions_by_total_iteration_count( + fork=fork, + total_iterations=total_iterations, + sender=attack_sender, + to=attack_address, + calldata=calldata, + ) + ) + else: + attack_txs = list( + run_code.transactions_by_gas_limit( + fork=fork, + gas_limit=gas_benchmark_value, + sender=attack_sender, + to=attack_address, + calldata=calldata, + ) + ) + + if cache_strategy == CacheStrategy.CACHE_PREVIOUS_BLOCK: + with TestPhaseManager.setup(): + cache_sender = pre.fund_eoa() + for tx in attack_txs: + cache_txs.append( + Transaction( + gas_limit=tx.gas_limit, + data=tx.data, + to=attack_address, + sender=cache_sender, + ) + ) + + blocks = build_cache_strategy_blocks(cache_strategy, attack_txs, cache_txs) + + benchmark_test( + pre=pre, + post=post, + blocks=blocks, + target_opcode=target_opcode, + skip_gas_used_validation=True, + expected_receipt_status=1, + ) From 97195440e93aeae29ae2629a364c888b85cf5c9c Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Wed, 17 Jun 2026 16:58:54 +0800 Subject: [PATCH 4/7] refactor: ether transfer benchmark --- .../bloatnet/test_transaction_types.py | 157 +++++++----------- 1 file changed, 62 insertions(+), 95 deletions(-) diff --git a/tests/benchmark/stateful/bloatnet/test_transaction_types.py b/tests/benchmark/stateful/bloatnet/test_transaction_types.py index 171c12a9e0..11464a985d 100644 --- a/tests/benchmark/stateful/bloatnet/test_transaction_types.py +++ b/tests/benchmark/stateful/bloatnet/test_transaction_types.py @@ -19,6 +19,11 @@ keccak256, ) +from tests.benchmark.helper.account_creator import ( + AccountCreator, + AccountMode, +) + # Deterministic sender pool of 15K accounts. # Funded via system contract withdrawals (funding.txt) in payload generation. # Placed outside pre-allocation to ensure accounts remain uncached. @@ -33,56 +38,9 @@ def yield_distinct_sender() -> Generator[EOA, None, None]: yield EOA(key=SENDER_BASE_KEY + i) -def build_unique_contract_initcode() -> bytes: - """ - Deployed runtime contract layout. - - offset size contents - ------ ---- -------------------------------- - 0x0000 4 PUSH2 0x5FFF; JUMP <- entry - 0x0004 28 JUMPDEST padding - 0x0020 12 JUMPDEST padding - 0x002C 20 contract ADDRESS <- unique - 0x0040 24512 JUMPDEST <- 0x5FFF lands here - 0x6000 STOP - - Embedded ADDRESS makes runtime unique per contract; - initcode and its CREATE2 hash is shared across all salts. - """ - max_code_size = 0x6000 # EIP-170 contract code size limit - - # MCOPY fills MEM[0:0x8000] with JUMPDEST. - # Runtime only uses MEM[0:0x6000]. - code = Op.MSTORE(0, bytes(Op.JUMPDEST * 32)) - for size in (1 << s for s in range(5, 15)): - code += Op.MCOPY(size, 0, size) - - # Runtime entry: JUMP to final JUMPDEST, then STOP. - entry = Op.JUMP(max_code_size - 1) - entry += Op.JUMPDEST * (32 - len(entry)) # Padding - - code += Op.MSTORE(0, bytes(entry)) - - # Mask ADDRESS into a JUMPDEST template via OR: - # bytes 0..12 bytes 12..32 - # ----------- ------------ - # ADDRESS 00 .. 00 <20-byte address> - # addr_slot 5b .. 5b 00 .. 00 - # OR result 5b .. 5b <20-byte address> - addr_slot = Op.JUMPDEST * 12 + Op.STOP * 20 - code += Op.MSTORE(0x20, Op.OR(Op.ADDRESS, bytes(addr_slot))) - - code += Op.RETURN(0, max_code_size) - - return bytes(code) - - -JOCHEMNET_UNIQUE_CONTRACT_INITCODE = build_unique_contract_initcode() - - -def yield_distinct_unique_code_jumpdest_receiver() -> Generator[ - Address, None, None -]: +def yield_distinct_create2_receiver( + initcode: bytes, +) -> Generator[Address, None, None]: """ Yield contract addresses deployed by the deterministic CREATE2 factory. """ @@ -90,7 +48,7 @@ def yield_distinct_unique_code_jumpdest_receiver() -> Generator[ yield compute_create2_address( address=DETERMINISTIC_FACTORY_ADDRESS, salt=salt, - initcode=JOCHEMNET_UNIQUE_CONTRACT_INITCODE, + initcode=initcode, ) @@ -130,10 +88,14 @@ def yield_distinct_nonexistent_receiver() -> Generator[Address, None, None]: @pytest.mark.parametrize( "case_id", [ + "diff_to_self", "diff_to_nonexistent", "diff_to_existent", "diff_to_contract", "diff_to_unique_code_jumpdest_contract", + "diff_to_contract_minimal", + "diff_to_contract_same", + "diff_to_contract_diff", ], ) @pytest.mark.parametrize("transfer_amount", [0, 1]) @@ -145,59 +107,64 @@ def test_ether_transfers_onchain_receivers( fork: Fork, gas_benchmark_value: int, ) -> None: - """ - Ether transfers to receivers that exist on-chain at run time. - - Scenarios: - - diff_to_nonexistent: distinct nonexistent receivers - (matches AccountMode.NON_EXISTING_ACCOUNT) - - diff_to_existent: distinct existent EOA receivers - (matches AccountMode.EXISTING_EOA) - - diff_to_contract: distinct contract receivers - (matches AccountMode.EXISTING_CONTRACT) - - diff_to_unique_code_jumpdest_contract: distinct CREATE2 contract - receivers each holding unique deployed code - """ + """Benchmark ether transfers across different receiver account types.""" senders = yield_distinct_sender() receiver_execution_gas = 0 - if case_id == "diff_to_nonexistent": - receivers = yield_distinct_nonexistent_receiver() - elif case_id == "diff_to_existent": - receivers = yield_distinct_existent_receiver() - elif case_id == "diff_to_contract": - receivers = yield_distinct_contract_receiver() - # Runtime code is the same across all the receivers - # Example contract: https://etherscan.io/address/0xa888df3ef62286dde06a79395760b9bce6c83c83#code - runtime = ( - Op.MSTORE(0x40, 0x60, new_memory_size=0x60) - + Op.JUMPI(Op.PUSH2(0x49), Op.ISZERO(Op.CALLDATASIZE)) - + Op.JUMPDEST * 3 - + Op.JUMP(Op.PUSH2(0x50)) - + Op.JUMPDEST - ) - receiver_execution_gas = runtime.gas_cost(fork) - elif case_id == "diff_to_unique_code_jumpdest_contract": - receivers = yield_distinct_unique_code_jumpdest_receiver() - # Runtime code aligns entry code path. - runtime = Op.JUMP(Op.PUSH2(0x5FFF)) + Op.JUMPDEST - receiver_execution_gas = runtime.gas_cost(fork) - else: - raise ValueError(f"Unknown case: {case_id}") + receivers: Generator[Address, None, None] + match case_id: + case "diff_to_self": + receivers = senders + case "diff_to_nonexistent": + receivers = yield_distinct_nonexistent_receiver() + case "diff_to_existent": + receivers = yield_distinct_existent_receiver() + case "diff_to_contract": + receivers = yield_distinct_contract_receiver() + # Runtime code is the same across all the receivers + # Example contract: https://etherscan.io/address/0xa888df3ef62286dde06a79395760b9bce6c83c83#code + runtime = ( + Op.MSTORE(0x40, 0x60, new_memory_size=0x60) + + Op.JUMPI(Op.PUSH2(0x49), Op.ISZERO(Op.CALLDATASIZE)) + + Op.JUMPDEST * 3 + + Op.JUMP(Op.PUSH2(0x50)) + + Op.JUMPDEST + ) + receiver_execution_gas = runtime.gas_cost(fork) + case "diff_to_unique_code_jumpdest_contract": + creator = AccountCreator(AccountMode.EXISTING_CONTRACT_JUMPDEST) + receivers = yield_distinct_create2_receiver(creator.initcode) + receiver_execution_gas = creator.runtime_code.gas_cost(fork) + case "diff_to_contract_minimal": + receivers = yield_distinct_create2_receiver( + AccountCreator(AccountMode.EXISTING_CONTRACT_MINIMAL).initcode + ) + case "diff_to_contract_same": + receivers = yield_distinct_create2_receiver( + AccountCreator(AccountMode.EXISTING_CONTRACT_SAME).initcode + ) + case "diff_to_contract_diff": + receivers = yield_distinct_create2_receiver( + AccountCreator(AccountMode.EXISTING_CONTRACT_DIFF).initcode + ) + case _: + raise ValueError(f"Unknown case: {case_id}") iteration_cost = ( fork.transaction_intrinsic_cost_calculator()() + receiver_execution_gas ) iteration_count = gas_benchmark_value // iteration_cost - txs = [ - Transaction( - to=next(receivers), - value=transfer_amount, - gas_limit=iteration_cost, - sender=next(senders), + txs = [] + for _ in range(iteration_count): + sender = next(senders) + txs.append( + Transaction( + to=sender if case_id == "diff_to_self" else next(receivers), + value=transfer_amount, + gas_limit=iteration_cost, + sender=sender, + ) ) - for _ in range(iteration_count) - ] benchmark_test( pre=pre, From 4727dce6fd8de5fce514d4bf31c0695cefde317b Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Wed, 17 Jun 2026 16:59:13 +0800 Subject: [PATCH 5/7] feat: add contract deployment script --- .../stateful/bloatnet/test_setup_contracts.py | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 tests/benchmark/stateful/bloatnet/test_setup_contracts.py diff --git a/tests/benchmark/stateful/bloatnet/test_setup_contracts.py b/tests/benchmark/stateful/bloatnet/test_setup_contracts.py new file mode 100644 index 0000000000..2def34879c --- /dev/null +++ b/tests/benchmark/stateful/bloatnet/test_setup_contracts.py @@ -0,0 +1,88 @@ +"""Deploy the CREATE2 contracts for benchmarks.""" + +from execution_testing import ( + DETERMINISTIC_FACTORY_ADDRESS, + Alloc, + BenchmarkTestFiller, + Fork, + Hash, + Op, + Transaction, +) + +from tests.benchmark.helper.account_creator import ( + AccountCreator, + AccountMode, +) +from tests.benchmark.stateful.helpers import ( + pack_transactions_into_blocks, +) + +RECEIVER_CONTRACT_COUNT = 120_000 + +CONTRACT_MODES = [ + AccountMode.EXISTING_CONTRACT_MINIMAL, + AccountMode.EXISTING_CONTRACT_SAME, + AccountMode.EXISTING_CONTRACT_DIFF, +] + + +def deployment_gas_limit( + fork: Fork, initcode: bytes, runtime_size: int +) -> int: + """ + Return the gas limit for one CREATE2 deployment, derived from the + intrinsic, CREATE2, and code-deposit costs with a small margin. + """ + intrinsic = fork.transaction_intrinsic_cost_calculator()( + calldata=Hash(0) + initcode + ) + create_cost = Op.CREATE2( + value=0, + offset=0, + size=len(initcode), + salt=0, + init_code_size=len(initcode), + ).gas_cost(fork) + deposit_cost = Op.RETURN( + 0, + runtime_size, + code_deposit_size=runtime_size, + ).gas_cost(fork) + base = intrinsic + create_cost + deposit_cost + return base + base // 16 + + +def test_deploy_existing_contracts( + benchmark_test: BenchmarkTestFiller, + pre: Alloc, + fork: Fork, + gas_benchmark_value: int, +) -> None: + """ + Deploy the contracts behind the `AccountMode.EXISTING_CONTRACT_*` + receivers via the deterministic CREATE2 factory. + """ + txs = [] + for account_mode in CONTRACT_MODES: + creator = AccountCreator(account_mode) + initcode = creator.initcode + gas_limit = deployment_gas_limit(fork, initcode, creator.runtime_size) + sender = pre.fund_eoa() + for salt in range(RECEIVER_CONTRACT_COUNT): + txs.append( + Transaction( + to=DETERMINISTIC_FACTORY_ADDRESS, + data=Hash(salt) + initcode, + gas_limit=gas_limit, + sender=sender, + ) + ) + + blocks = pack_transactions_into_blocks(txs, gas_benchmark_value) + + benchmark_test( + blocks=blocks, + skip_gas_used_validation=True, + expected_receipt_status=1, + ) From 4a66a2e8b61c3c5ba32245e5f4be2782fbf96d1c Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Wed, 17 Jun 2026 22:24:25 +0800 Subject: [PATCH 6/7] feat: add eoa delegation target --- .../helper/account_sender_receiver.py | 80 +++++++++++++++++++ .../stateful/bloatnet/test_setup_contracts.py | 58 +++++++++++++- .../bloatnet/test_transaction_types.py | 74 +++-------------- 3 files changed, 146 insertions(+), 66 deletions(-) create mode 100644 tests/benchmark/helper/account_sender_receiver.py diff --git a/tests/benchmark/helper/account_sender_receiver.py b/tests/benchmark/helper/account_sender_receiver.py new file mode 100644 index 0000000000..c3a7ff1581 --- /dev/null +++ b/tests/benchmark/helper/account_sender_receiver.py @@ -0,0 +1,80 @@ +"""Deterministic benchmark sender and receiver accounts.""" + +import itertools +from typing import Generator + +from execution_testing import ( + DETERMINISTIC_FACTORY_ADDRESS, + EOA, + Address, + compute_create2_address, + compute_create_address, + keccak256, +) + +# Deterministic sender pool, pre-funded via system-contract withdrawals +# (funding.txt) during payload generation. Kept out of the pre-allocation so +# the accounts stay uncached. +SENDER_BASE_KEY = int.from_bytes( + keccak256(b"gas-repricings-private-key"), "big" +) + +# Deterministic EIP-7702 delegate authorities: +# Authority i delegates to EXISTING_CONTRACT_DIFF receiver i. +DELEGATE_BASE_KEY = int.from_bytes( + keccak256(b"gas-repricings-7702-delegate"), "big" +) + +# Bittrex controller mainnet address: it created 1.5M contracts via CREATE with +# deterministic addresses, none self-destructed. Used as existing-contract +# receivers. +BITTREX_CONTROLLER_ADDRESS = Address( + 0xA3C1E324CA1CE40DB73ED6026C4A177F099B5770 +) + + +def yield_distinct_sender() -> Generator[EOA, None, None]: + """Yield deterministic sender EOAs pre-funded on-chain.""" + for i in itertools.count(0): + yield EOA(key=SENDER_BASE_KEY + i) + + +def yield_distinct_create2_receiver( + initcode: bytes, +) -> Generator[Address, None, None]: + """Yield addresses deployed by the deterministic CREATE2 factory.""" + for salt in itertools.count(0): + yield compute_create2_address( + address=DETERMINISTIC_FACTORY_ADDRESS, + salt=salt, + initcode=initcode, + ) + + +def yield_distinct_contract_receiver() -> Generator[Address, None, None]: + """Yield contracts created by the Bittrex controller via CREATE.""" + for nonce in itertools.count(2): + yield compute_create_address( + address=BITTREX_CONTROLLER_ADDRESS, nonce=nonce + ) + + +def yield_distinct_existent_receiver() -> Generator[Address, None, None]: + """ + Yield existing balance-only EOAs on bloatnet, pre-funded by Spamoor + (https://github.com/CPerezz/spamoor/pull/12). + """ + for address in itertools.count(0x1000): + yield Address(address) + + +def yield_distinct_nonexistent_receiver() -> Generator[Address, None, None]: + """Yield non-existent accounts starting from keccak256('random').""" + for address in itertools.count(0xF3CF193BB4AF1022AF7D2089F37D8BAE7157B85F): + yield Address(address) + + +def yield_distinct_delegate_receiver() -> Generator[Address, None, None]: + """Yield EOA that delegates to distinct EXISTING_CONTRACT_DIFF receiver.""" + for i in itertools.count(0): + yield EOA(key=DELEGATE_BASE_KEY + i) diff --git a/tests/benchmark/stateful/bloatnet/test_setup_contracts.py b/tests/benchmark/stateful/bloatnet/test_setup_contracts.py index 2def34879c..2224947ccf 100644 --- a/tests/benchmark/stateful/bloatnet/test_setup_contracts.py +++ b/tests/benchmark/stateful/bloatnet/test_setup_contracts.py @@ -2,21 +2,29 @@ from execution_testing import ( DETERMINISTIC_FACTORY_ADDRESS, + EOA, + Account, Alloc, + AuthorizationTuple, BenchmarkTestFiller, Fork, Hash, Op, Transaction, + compute_create2_address, ) from tests.benchmark.helper.account_creator import ( AccountCreator, AccountMode, ) +from tests.benchmark.helper.account_sender_receiver import ( + DELEGATE_BASE_KEY, +) from tests.benchmark.stateful.helpers import ( pack_transactions_into_blocks, ) +from tests.prague.eip7702_set_code_tx.spec import Spec as Spec7702 RECEIVER_CONTRACT_COUNT = 120_000 @@ -58,12 +66,16 @@ def test_deploy_existing_contracts( pre: Alloc, fork: Fork, gas_benchmark_value: int, + tx_gas_limit: int, ) -> None: """ Deploy the contracts behind the `AccountMode.EXISTING_CONTRACT_*` receivers via the deterministic CREATE2 factory. + + Delegate deterministic EOAs to EXISTING_CONTRACT_DIFF receivers. """ txs = [] + post: dict = {} for account_mode in CONTRACT_MODES: creator = AccountCreator(account_mode) initcode = creator.initcode @@ -79,10 +91,52 @@ def test_deploy_existing_contracts( ) ) - blocks = pack_transactions_into_blocks(txs, gas_benchmark_value) + # Delegate authority i to the i-th DIFF receiver (EIP-7702). + delegation_sender = pre.fund_eoa() + intrinsic = fork.transaction_intrinsic_cost_calculator() + # DIFF receivers share one initcode; build it once for CREATE2 derivation. + diff_initcode = AccountCreator(AccountMode.EXISTING_CONTRACT_DIFF).initcode + + base_gas = intrinsic(authorization_list_or_count=0) + per_auth_gas = intrinsic(authorization_list_or_count=1) - base_gas + gas_buffer = 100_000 + auths_per_tx = max( + 1, (tx_gas_limit - gas_buffer - base_gas) // per_auth_gas + ) + + for start in range(0, RECEIVER_CONTRACT_COUNT, auths_per_tx): + count = min(auths_per_tx, RECEIVER_CONTRACT_COUNT - start) + authorization_list = [] + for i in range(start, start + count): + authority = EOA(key=DELEGATE_BASE_KEY + i) + target = compute_create2_address( + address=DETERMINISTIC_FACTORY_ADDRESS, + salt=i, + initcode=diff_initcode, + ) + authorization_list.append( + AuthorizationTuple(address=target, nonce=0, signer=authority) + ) + if i == 0 or i == RECEIVER_CONTRACT_COUNT - 1: + post[authority] = Account( + nonce=1, + code=Spec7702.delegation_designation(target), + ) + + txs.append( + Transaction( + to=delegation_sender, + gas_limit=( + intrinsic(authorization_list_or_count=count) + gas_buffer + ), + sender=delegation_sender, + authorization_list=authorization_list, + ) + ) benchmark_test( - blocks=blocks, + post=post, + blocks=pack_transactions_into_blocks(txs, gas_benchmark_value), skip_gas_used_validation=True, expected_receipt_status=1, ) diff --git a/tests/benchmark/stateful/bloatnet/test_transaction_types.py b/tests/benchmark/stateful/bloatnet/test_transaction_types.py index 11464a985d..837d853c1b 100644 --- a/tests/benchmark/stateful/bloatnet/test_transaction_types.py +++ b/tests/benchmark/stateful/bloatnet/test_transaction_types.py @@ -1,12 +1,9 @@ """Benchmark ether transfers to receivers that exist on-chain.""" -import itertools from typing import Generator import pytest from execution_testing import ( - DETERMINISTIC_FACTORY_ADDRESS, - EOA, Address, Alloc, BenchmarkTestFiller, @@ -14,76 +11,22 @@ Fork, Op, Transaction, - compute_create2_address, - compute_create_address, - keccak256, ) from tests.benchmark.helper.account_creator import ( AccountCreator, AccountMode, ) - -# Deterministic sender pool of 15K accounts. -# Funded via system contract withdrawals (funding.txt) in payload generation. -# Placed outside pre-allocation to ensure accounts remain uncached. -SENDER_BASE_KEY = int.from_bytes( - keccak256(b"gas-repricings-private-key"), "big" -) - - -def yield_distinct_sender() -> Generator[EOA, None, None]: - """Yield deterministic sender EOAs pre-funded on-chain.""" - for i in itertools.count(0): - yield EOA(key=SENDER_BASE_KEY + i) - - -def yield_distinct_create2_receiver( - initcode: bytes, -) -> Generator[Address, None, None]: - """ - Yield contract addresses deployed by the deterministic CREATE2 factory. - """ - for salt in itertools.count(0): - yield compute_create2_address( - address=DETERMINISTIC_FACTORY_ADDRESS, - salt=salt, - initcode=initcode, - ) - - -# Bittrex controller mainnet address -# Creates 1.5M contracts with deterministic address via CREATE -# It is guaranteed no contract is destructed -# Used for existing contract targets in benchmark -BITTREX_CONTROLLER_ADDRESS = Address( - 0xA3C1E324CA1CE40DB73ED6026C4A177F099B5770 +from tests.benchmark.helper.account_sender_receiver import ( + yield_distinct_contract_receiver, + yield_distinct_create2_receiver, + yield_distinct_delegate_receiver, + yield_distinct_existent_receiver, + yield_distinct_nonexistent_receiver, + yield_distinct_sender, ) -def yield_distinct_contract_receiver() -> Generator[Address, None, None]: - """Yield contract account created by Bittrex controller via CREATE.""" - for nonce in itertools.count(2): - yield compute_create_address( - address=BITTREX_CONTROLLER_ADDRESS, nonce=nonce - ) - - -def yield_distinct_existent_receiver() -> Generator[Address, None, None]: - """ - Yield existing balance-only EOA on bloatnet. pre-funded by Spamoor - (https://github.com/CPerezz/spamoor/pull/12). - """ - for address in itertools.count(0x1000): - yield Address(address) - - -def yield_distinct_nonexistent_receiver() -> Generator[Address, None, None]: - """Yield non-existent accounts starting from keccak256('random').""" - for address in itertools.count(0xF3CF193BB4AF1022AF7D2089F37D8BAE7157B85F): - yield Address(address) - - @pytest.mark.repricing @pytest.mark.parametrize( "case_id", @@ -96,6 +39,7 @@ def yield_distinct_nonexistent_receiver() -> Generator[Address, None, None]: "diff_to_contract_minimal", "diff_to_contract_same", "diff_to_contract_diff", + "diff_to_delegated_contract_diff", ], ) @pytest.mark.parametrize("transfer_amount", [0, 1]) @@ -146,6 +90,8 @@ def test_ether_transfers_onchain_receivers( receivers = yield_distinct_create2_receiver( AccountCreator(AccountMode.EXISTING_CONTRACT_DIFF).initcode ) + case "diff_to_delegated_contract_diff": + receivers = yield_distinct_delegate_receiver() case _: raise ValueError(f"Unknown case: {case_id}") From 5c3eb9eae8249d14a1348a4efebd8e3dc03bf191 Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Fri, 19 Jun 2026 13:05:05 +0800 Subject: [PATCH 7/7] temp --- tests/benchmark/stateful/bloatnet/test_account_query.py | 2 +- tests/benchmark/stateful/bloatnet/test_setup_contracts.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/benchmark/stateful/bloatnet/test_account_query.py b/tests/benchmark/stateful/bloatnet/test_account_query.py index 75be02af44..d0dd930cd3 100644 --- a/tests/benchmark/stateful/bloatnet/test_account_query.py +++ b/tests/benchmark/stateful/bloatnet/test_account_query.py @@ -139,7 +139,7 @@ def account_access_params() -> list: @pytest.mark.repricing -@pytest.mark.parametrize("cache_strategy", CacheStrategy.NO_CACHE) +@pytest.mark.parametrize("cache_strategy", [CacheStrategy.NO_CACHE]) @pytest.mark.parametrize( "opcode,value_sent,account_mode,overhead_baseline", account_access_params() ) diff --git a/tests/benchmark/stateful/bloatnet/test_setup_contracts.py b/tests/benchmark/stateful/bloatnet/test_setup_contracts.py index 2224947ccf..f738ab420e 100644 --- a/tests/benchmark/stateful/bloatnet/test_setup_contracts.py +++ b/tests/benchmark/stateful/bloatnet/test_setup_contracts.py @@ -26,7 +26,7 @@ ) from tests.prague.eip7702_set_code_tx.spec import Spec as Spec7702 -RECEIVER_CONTRACT_COUNT = 120_000 +RECEIVER_CONTRACT_COUNT = 12_000 CONTRACT_MODES = [ AccountMode.EXISTING_CONTRACT_MINIMAL,