From 8c8c2fe61d77bd3e9a318fb0f34415e12c8eff96 Mon Sep 17 00:00:00 2001 From: Jochem Brouwer Date: Tue, 12 May 2026 05:51:37 +0200 Subject: [PATCH 01/10] (Claude): add eth transfer cases for repricing --- .../scenario/test_transaction_types.py | 99 ++++++++++++++++++- 1 file changed, 97 insertions(+), 2 deletions(-) diff --git a/tests/benchmark/compute/scenario/test_transaction_types.py b/tests/benchmark/compute/scenario/test_transaction_types.py index b23d3180d22..48b1bf9688a 100644 --- a/tests/benchmark/compute/scenario/test_transaction_types.py +++ b/tests/benchmark/compute/scenario/test_transaction_types.py @@ -19,6 +19,7 @@ Op, Transaction, compute_create_address, + keccak256, ) @@ -73,6 +74,61 @@ def get_single_receiver_list( yield receiver +# Bittrex Controller: created 1,586,350 contracts on mainnet that cannot +# selfdestruct, so they are guaranteed to be on-chain. Safe for benchmarks +# up to ~300M gas (at 2000 gas per cold address). +BITTREX_CONTROLLER_ADDRESS = Address( + 0xA3C1E324CA1CE40DB73ED6026C4A177F099B5770 +) + + +def get_distinct_contract_receiver_list() -> Generator[Address, None, None]: + """ + Yield addresses of contracts created by the Bittrex Controller, + starting at nonce 1. + """ + nonce = 1 + while True: + yield compute_create_address( + address=BITTREX_CONTROLLER_ADDRESS, nonce=nonce + ) + nonce += 1 + + +def get_distinct_existent_receiver_list() -> Generator[Address, None, None]: + """ + Yield sequential EOA addresses starting at 0x1000. + + The Spamoor EOA creator + (https://github.com/CPerezz/spamoor/pull/12) funded these addresses + on bloatnet. + """ + address = 0x1000 + while True: + yield Address(address) + address += 1 + + +def get_distinct_nonexistent_receiver_list() -> Generator[ + Address, None, None +]: + """Yield sequential addresses starting at keccak256("random").""" + address = int.from_bytes(keccak256(b"random")[-20:], "big") + while True: + yield Address(address) + address += 1 + + +# Cases where the receiver address is determined by case_id rather than +# being constructed in pre-state. The receiver_account_type parametrization +# is not multiplied with these. +RECEIVER_TYPED_CASES: set[str] = { + "diff_to_nonexistent", + "diff_to_existent", + "diff_to_contract", +} + + @dataclass(frozen=True) class ReceiverAccountType: """Receiver account type for ether transfer benchmarks.""" @@ -120,6 +176,21 @@ def ether_transfer_case( senders = get_distinct_sender_list(pre) receivers = get_distinct_receiver_list(pre, balance, delegation) + elif case_id == "diff_to_nonexistent": + """Multiple senders → distinct nonexistent receivers.""" + senders = get_distinct_sender_list(pre) + receivers = get_distinct_nonexistent_receiver_list() + + elif case_id == "diff_to_existent": + """Multiple senders → distinct existent EOA receivers.""" + senders = get_distinct_sender_list(pre) + receivers = get_distinct_existent_receiver_list() + + elif case_id == "diff_to_contract": + """Multiple senders → distinct contract receivers.""" + senders = get_distinct_sender_list(pre) + receivers = get_distinct_contract_receiver_list() + else: raise ValueError(f"Unknown case: {case_id}") @@ -134,6 +205,9 @@ def ether_transfer_case( "diff_acc_to_b", "a_to_diff_acc", "diff_acc_to_diff_acc", + "diff_to_nonexistent", + "diff_to_existent", + "diff_to_contract", ], ) @pytest.mark.parametrize("transfer_amount", [0, 1]) @@ -177,13 +251,34 @@ def test_ether_transfers( - diff_acc_to_b: multiple senders → one receiver - a_to_diff_acc: one sender → multiple receivers - diff_acc_to_diff_acc: multiple senders → multiple receivers + - diff_to_nonexistent: multiple senders → distinct nonexistent + receivers (matches AccountMode.NON_EXISTING_ACCOUNT) + - diff_to_existent: multiple senders → distinct existent EOA + receivers (matches AccountMode.EXISTING_EOA) + - diff_to_contract: multiple senders → distinct contract receivers + (matches AccountMode.EXISTING_CONTRACT) When warm_access is True, each transaction includes an access list entry for the receiver to warm the account before the transfer. """ - senders, receivers = ether_transfer_case + if case_id in RECEIVER_TYPED_CASES: + # Receiver address is determined by case_id; avoid multiplying with + # receiver_account_type and only run for the default variant. + if receiver_account_type != ReceiverAccountType( + balance=0, delegated=False + ): + pytest.skip( + "Receiver address is determined by case_id; skipping " + "non-default receiver_account_type." + ) + # Receivers are not allocated in pre-state during fill (they are + # expected to already exist on-chain at run time, e.g. on bloatnet), + # so their initial balance during fill is 0. + balance = 0 + else: + balance = receiver_account_type.balance - balance = receiver_account_type.balance + senders, receivers = ether_transfer_case txs = [] token_transfers: dict[Address, int] = {} From e6623567dabdc9af4cfcc720450410553da68c5e Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Tue, 12 May 2026 13:28:58 +0800 Subject: [PATCH 02/10] refactor: split test based on pre-alloc --- .../scenario/test_transaction_types.py | 322 +++++++++--------- 1 file changed, 156 insertions(+), 166 deletions(-) diff --git a/tests/benchmark/compute/scenario/test_transaction_types.py b/tests/benchmark/compute/scenario/test_transaction_types.py index 48b1bf9688a..1c1eeff69be 100644 --- a/tests/benchmark/compute/scenario/test_transaction_types.py +++ b/tests/benchmark/compute/scenario/test_transaction_types.py @@ -1,9 +1,10 @@ """Benchmark different transaction types.""" +import itertools import math import random from dataclasses import dataclass -from typing import Generator, List, Tuple +from typing import Generator, List import pytest from execution_testing import ( @@ -19,7 +20,6 @@ Op, Transaction, compute_create_address, - keccak256, ) @@ -74,59 +74,36 @@ def get_single_receiver_list( yield receiver -# Bittrex Controller: created 1,586,350 contracts on mainnet that cannot -# selfdestruct, so they are guaranteed to be on-chain. Safe for benchmarks -# up to ~300M gas (at 2000 gas per cold address). +# Bitterex 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 ) def get_distinct_contract_receiver_list() -> Generator[Address, None, None]: - """ - Yield addresses of contracts created by the Bittrex Controller, - starting at nonce 1. - """ - nonce = 1 - while True: + """Yield contract account created by Bitterex controller via CREATE.""" + for nonce in itertools.count(1): yield compute_create_address( address=BITTREX_CONTROLLER_ADDRESS, nonce=nonce ) - nonce += 1 def get_distinct_existent_receiver_list() -> Generator[Address, None, None]: """ - Yield sequential EOA addresses starting at 0x1000. - - The Spamoor EOA creator - (https://github.com/CPerezz/spamoor/pull/12) funded these addresses - on bloatnet. + Yield existing balance-only EOA on bloatnet. pre-funded by Spamoor + (https://github.com/CPerezz/spamoor/pull/12). """ - address = 0x1000 - while True: + for address in itertools.count(0x1000): yield Address(address) - address += 1 -def get_distinct_nonexistent_receiver_list() -> Generator[ - Address, None, None -]: - """Yield sequential addresses starting at keccak256("random").""" - address = int.from_bytes(keccak256(b"random")[-20:], "big") - while True: +def get_distinct_nonexistent_receiver_list() -> Generator[Address, None, None]: + """Yield non-existent accounts starting from keccak256('random').""" + for address in itertools.count(0xF3CF193BB4AF1022AF7D2089F37D8BAE7157B85F): yield Address(address) - address += 1 - - -# Cases where the receiver address is determined by case_id rather than -# being constructed in pre-state. The receiver_account_type parametrization -# is not multiplied with these. -RECEIVER_TYPED_CASES: set[str] = { - "diff_to_nonexistent", - "diff_to_existent", - "diff_to_contract", -} @dataclass(frozen=True) @@ -137,64 +114,68 @@ class ReceiverAccountType: delegated: bool -@pytest.fixture -def ether_transfer_case( - case_id: str, +def _run_ether_transfer_benchmark( + benchmark_test: BenchmarkTestFiller, pre: Alloc, - receiver_account_type: ReceiverAccountType, -) -> Tuple[Generator[Address, None, None], Generator[Address, None, None]]: - """Generate sender and receiver generators based on the test case.""" - balance = receiver_account_type.balance - delegation = ( - pre.deploy_contract(code=Op.STOP) - if receiver_account_type.delegated - else None + fork: Fork, + gas_benchmark_value: int, + senders: Generator[Address, None, None], + receivers: Generator[Address, None, None], + transfer_amount: int, + warm_access: bool, + receiver_initial_balance: int, + track_post_state: bool, +) -> None: + """Fill a block with ether transfers between the given generators.""" + iteration_cost = fork.transaction_intrinsic_cost_calculator()( + access_list=( + [AccessList(address=Address(0x100), storage_keys=[])] + if warm_access + else None + ), ) + iteration_count = gas_benchmark_value // iteration_cost - if case_id == "a_to_a": - """Sending to self.""" - senders = get_single_sender_list(pre) - receivers = senders - - elif case_id == "a_to_b": - """One sender → one receiver.""" - senders = get_single_sender_list(pre) - receivers = get_single_receiver_list(pre, balance, delegation) - - elif case_id == "diff_acc_to_b": - """Multiple senders → one receiver.""" - senders = get_distinct_sender_list(pre) - receivers = get_single_receiver_list(pre, balance, delegation) - - elif case_id == "a_to_diff_acc": - """One sender → multiple receivers.""" - senders = get_single_sender_list(pre) - receivers = get_distinct_receiver_list(pre, balance, delegation) - - elif case_id == "diff_acc_to_diff_acc": - """Multiple senders → multiple receivers.""" - senders = get_distinct_sender_list(pre) - receivers = get_distinct_receiver_list(pre, balance, delegation) - - elif case_id == "diff_to_nonexistent": - """Multiple senders → distinct nonexistent receivers.""" - senders = get_distinct_sender_list(pre) - receivers = get_distinct_nonexistent_receiver_list() - - elif case_id == "diff_to_existent": - """Multiple senders → distinct existent EOA receivers.""" - senders = get_distinct_sender_list(pre) - receivers = get_distinct_existent_receiver_list() - - elif case_id == "diff_to_contract": - """Multiple senders → distinct contract receivers.""" - senders = get_distinct_sender_list(pre) - receivers = get_distinct_contract_receiver_list() + txs = [] + token_transfers: dict[Address, int] = {} + for _ in range(iteration_count): + receiver = next(receivers) + token_transfers[receiver] = ( + token_transfers.get(receiver, 0) + transfer_amount + ) + access_list = ( + [AccessList(address=receiver, storage_keys=[])] + if warm_access + else None + ) + txs.append( + Transaction( + to=receiver, + value=transfer_amount, + gas_limit=iteration_cost, + sender=next(senders), + access_list=access_list, + ) + ) - else: - raise ValueError(f"Unknown case: {case_id}") + post_state = ( + { + receiver: Account( + balance=receiver_initial_balance + transferred_amount + ) + for receiver, transferred_amount in token_transfers.items() + if receiver_initial_balance + transferred_amount > 0 + } + if track_post_state + else {} + ) - return senders, receivers + benchmark_test( + pre=pre, + post=post_state, + blocks=[Block(txs=txs)], + expected_benchmark_gas_used=iteration_count * iteration_cost, + ) @pytest.mark.parametrize( @@ -205,9 +186,6 @@ def ether_transfer_case( "diff_acc_to_b", "a_to_diff_acc", "diff_acc_to_diff_acc", - "diff_to_nonexistent", - "diff_to_existent", - "diff_to_contract", ], ) @pytest.mark.parametrize("transfer_amount", [0, 1]) @@ -238,95 +216,107 @@ def test_ether_transfers( fork: Fork, gas_benchmark_value: int, warm_access: bool, - ether_transfer_case: Tuple[ - Generator[Address, None, None], Generator[Address, None, None] - ], ) -> None: """ - Single test for ether transfer scenarios. + Ether transfers where receivers constructed in pre-allocation. Scenarios: - - a_to_a: one sender → one sender + - a_to_a: self-transfer - a_to_b: one sender → one receiver - diff_acc_to_b: multiple senders → one receiver - a_to_diff_acc: one sender → multiple receivers - diff_acc_to_diff_acc: multiple senders → multiple receivers - - diff_to_nonexistent: multiple senders → distinct nonexistent - receivers (matches AccountMode.NON_EXISTING_ACCOUNT) - - diff_to_existent: multiple senders → distinct existent EOA - receivers (matches AccountMode.EXISTING_EOA) - - diff_to_contract: multiple senders → distinct contract receivers - (matches AccountMode.EXISTING_CONTRACT) - - When warm_access is True, each transaction includes an access list - entry for the receiver to warm the account before the transfer. """ - if case_id in RECEIVER_TYPED_CASES: - # Receiver address is determined by case_id; avoid multiplying with - # receiver_account_type and only run for the default variant. - if receiver_account_type != ReceiverAccountType( - balance=0, delegated=False - ): - pytest.skip( - "Receiver address is determined by case_id; skipping " - "non-default receiver_account_type." - ) - # Receivers are not allocated in pre-state during fill (they are - # expected to already exist on-chain at run time, e.g. on bloatnet), - # so their initial balance during fill is 0. - balance = 0 - else: - balance = receiver_account_type.balance - - senders, receivers = ether_transfer_case + balance = receiver_account_type.balance + delegation = ( + pre.deploy_contract(code=Op.STOP) + if receiver_account_type.delegated + else None + ) - txs = [] - token_transfers: dict[Address, int] = {} + if case_id == "a_to_a": + senders = get_single_sender_list(pre) + receivers = senders + elif case_id == "a_to_b": + senders = get_single_sender_list(pre) + receivers = get_single_receiver_list(pre, balance, delegation) + elif case_id == "diff_acc_to_b": + senders = get_distinct_sender_list(pre) + receivers = get_single_receiver_list(pre, balance, delegation) + elif case_id == "a_to_diff_acc": + senders = get_single_sender_list(pre) + receivers = get_distinct_receiver_list(pre, balance, delegation) + elif case_id == "diff_acc_to_diff_acc": + senders = get_distinct_sender_list(pre) + receivers = get_distinct_receiver_list(pre, balance, delegation) + else: + raise ValueError(f"Unknown case: {case_id}") - iteration_cost = fork.transaction_intrinsic_cost_calculator()( - access_list=( - [AccessList(address=Address(0x100), storage_keys=[])] - if warm_access - else None - ), + _run_ether_transfer_benchmark( + benchmark_test=benchmark_test, + pre=pre, + fork=fork, + gas_benchmark_value=gas_benchmark_value, + senders=senders, + receivers=receivers, + transfer_amount=transfer_amount, + warm_access=warm_access, + receiver_initial_balance=balance, + track_post_state=(case_id != "a_to_a"), ) - iteration_count = gas_benchmark_value // iteration_cost - for _ in range(iteration_count): - receiver = next(receivers) - token_transfers[receiver] = ( - token_transfers.get(receiver, 0) + transfer_amount - ) - access_list = ( - [AccessList(address=receiver, storage_keys=[])] - if warm_access - else None - ) - txs.append( - Transaction( - to=receiver, - value=transfer_amount, - gas_limit=iteration_cost, - sender=next(senders), - access_list=access_list, - ) - ) - post_state = ( - {} - if case_id == "a_to_a" - else { - receiver: Account(balance=balance + transferred_amount) - for receiver, transferred_amount in token_transfers.items() - if balance + transferred_amount > 0 - } - ) +@pytest.mark.parametrize( + "case_id", + [ + "diff_to_nonexistent", + "diff_to_existent", + "diff_to_contract", + ], +) +@pytest.mark.parametrize("transfer_amount", [0, 1]) +@pytest.mark.parametrize("warm_access", [False, True]) +def test_ether_transfers_onchain_receivers( + benchmark_test: BenchmarkTestFiller, + pre: Alloc, + case_id: str, + transfer_amount: int, + fork: Fork, + gas_benchmark_value: int, + warm_access: bool, +) -> None: + """ + Ether transfers to receivers that exist on-chain at run time. - benchmark_test( + 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) + """ + senders = get_distinct_sender_list(pre) + if case_id == "diff_to_nonexistent": + receivers = get_distinct_nonexistent_receiver_list() + elif case_id == "diff_to_existent": + receivers = get_distinct_existent_receiver_list() + elif case_id == "diff_to_contract": + receivers = get_distinct_contract_receiver_list() + else: + raise ValueError(f"Unknown case: {case_id}") + + _run_ether_transfer_benchmark( + benchmark_test=benchmark_test, pre=pre, - post=post_state, - blocks=[Block(txs=txs)], - expected_benchmark_gas_used=iteration_count * iteration_cost, + fork=fork, + gas_benchmark_value=gas_benchmark_value, + senders=senders, + receivers=receivers, + transfer_amount=transfer_amount, + warm_access=warm_access, + receiver_initial_balance=0, + track_post_state=False, ) From 4c022346cc2f253743eaab4643fce0901b78fb75 Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Tue, 12 May 2026 13:46:38 +0800 Subject: [PATCH 03/10] refactor: bump execution cost for contract ether reception --- .../scenario/test_transaction_types.py | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/tests/benchmark/compute/scenario/test_transaction_types.py b/tests/benchmark/compute/scenario/test_transaction_types.py index 1c1eeff69be..873ee46b05a 100644 --- a/tests/benchmark/compute/scenario/test_transaction_types.py +++ b/tests/benchmark/compute/scenario/test_transaction_types.py @@ -83,6 +83,11 @@ def get_single_receiver_list( ) +# Ether reception cost for Bittrex-created contracts +# Exact: 51 gas, rounded up to 60. +RECEIVER_CONTRACT_EXECUTION_GAS = 60 + + def get_distinct_contract_receiver_list() -> Generator[Address, None, None]: """Yield contract account created by Bitterex controller via CREATE.""" for nonce in itertools.count(1): @@ -125,14 +130,18 @@ def _run_ether_transfer_benchmark( warm_access: bool, receiver_initial_balance: int, track_post_state: bool, + receiver_execution_gas: int = 0, ) -> None: """Fill a block with ether transfers between the given generators.""" - iteration_cost = fork.transaction_intrinsic_cost_calculator()( - access_list=( - [AccessList(address=Address(0x100), storage_keys=[])] - if warm_access - else None - ), + iteration_cost = ( + fork.transaction_intrinsic_cost_calculator()( + access_list=( + [AccessList(address=Address(0x100), storage_keys=[])] + if warm_access + else None + ), + ) + + receiver_execution_gas ) iteration_count = gas_benchmark_value // iteration_cost @@ -297,12 +306,14 @@ def test_ether_transfers_onchain_receivers( (matches AccountMode.EXISTING_CONTRACT) """ senders = get_distinct_sender_list(pre) + receiver_execution_gas = 0 if case_id == "diff_to_nonexistent": receivers = get_distinct_nonexistent_receiver_list() elif case_id == "diff_to_existent": receivers = get_distinct_existent_receiver_list() elif case_id == "diff_to_contract": receivers = get_distinct_contract_receiver_list() + receiver_execution_gas = RECEIVER_CONTRACT_EXECUTION_GAS else: raise ValueError(f"Unknown case: {case_id}") @@ -317,6 +328,7 @@ def test_ether_transfers_onchain_receivers( warm_access=warm_access, receiver_initial_balance=0, track_post_state=False, + receiver_execution_gas=receiver_execution_gas, ) From a8807d80b8719bb0f74cebd1d701d99081a1f63d Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Tue, 12 May 2026 15:06:23 +0800 Subject: [PATCH 04/10] chore: remove unnecessary parametrization --- tests/benchmark/compute/scenario/test_transaction_types.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/benchmark/compute/scenario/test_transaction_types.py b/tests/benchmark/compute/scenario/test_transaction_types.py index 873ee46b05a..92aa7ccba9d 100644 --- a/tests/benchmark/compute/scenario/test_transaction_types.py +++ b/tests/benchmark/compute/scenario/test_transaction_types.py @@ -84,8 +84,7 @@ def get_single_receiver_list( # Ether reception cost for Bittrex-created contracts -# Exact: 51 gas, rounded up to 60. -RECEIVER_CONTRACT_EXECUTION_GAS = 60 +RECEIVER_CONTRACT_EXECUTION_GAS = 51 def get_distinct_contract_receiver_list() -> Generator[Address, None, None]: @@ -284,7 +283,6 @@ def test_ether_transfers( ], ) @pytest.mark.parametrize("transfer_amount", [0, 1]) -@pytest.mark.parametrize("warm_access", [False, True]) def test_ether_transfers_onchain_receivers( benchmark_test: BenchmarkTestFiller, pre: Alloc, @@ -292,7 +290,6 @@ def test_ether_transfers_onchain_receivers( transfer_amount: int, fork: Fork, gas_benchmark_value: int, - warm_access: bool, ) -> None: """ Ether transfers to receivers that exist on-chain at run time. @@ -325,7 +322,7 @@ def test_ether_transfers_onchain_receivers( senders=senders, receivers=receivers, transfer_amount=transfer_amount, - warm_access=warm_access, + warm_access=False, receiver_initial_balance=0, track_post_state=False, receiver_execution_gas=receiver_execution_gas, From 71783bc4cf89f3afb5dfd632d0781d7cc42664f1 Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Tue, 12 May 2026 15:31:20 +0800 Subject: [PATCH 05/10] refactor: move new benchmark under stateful folder --- .../scenario/test_transaction_types.py | 274 ++++++------------ .../bloatnet/test_transaction_types.py | 120 ++++++++ 2 files changed, 210 insertions(+), 184 deletions(-) create mode 100644 tests/benchmark/stateful/bloatnet/test_transaction_types.py diff --git a/tests/benchmark/compute/scenario/test_transaction_types.py b/tests/benchmark/compute/scenario/test_transaction_types.py index 92aa7ccba9d..b23d3180d22 100644 --- a/tests/benchmark/compute/scenario/test_transaction_types.py +++ b/tests/benchmark/compute/scenario/test_transaction_types.py @@ -1,10 +1,9 @@ """Benchmark different transaction types.""" -import itertools import math import random from dataclasses import dataclass -from typing import Generator, List +from typing import Generator, List, Tuple import pytest from execution_testing import ( @@ -74,42 +73,6 @@ def get_single_receiver_list( yield receiver -# Bitterex 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 -) - - -# Ether reception cost for Bittrex-created contracts -RECEIVER_CONTRACT_EXECUTION_GAS = 51 - - -def get_distinct_contract_receiver_list() -> Generator[Address, None, None]: - """Yield contract account created by Bitterex controller via CREATE.""" - for nonce in itertools.count(1): - yield compute_create_address( - address=BITTREX_CONTROLLER_ADDRESS, nonce=nonce - ) - - -def get_distinct_existent_receiver_list() -> 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 get_distinct_nonexistent_receiver_list() -> Generator[Address, None, None]: - """Yield non-existent accounts starting from keccak256('random').""" - for address in itertools.count(0xF3CF193BB4AF1022AF7D2089F37D8BAE7157B85F): - yield Address(address) - - @dataclass(frozen=True) class ReceiverAccountType: """Receiver account type for ether transfer benchmarks.""" @@ -118,72 +81,49 @@ class ReceiverAccountType: delegated: bool -def _run_ether_transfer_benchmark( - benchmark_test: BenchmarkTestFiller, +@pytest.fixture +def ether_transfer_case( + case_id: str, pre: Alloc, - fork: Fork, - gas_benchmark_value: int, - senders: Generator[Address, None, None], - receivers: Generator[Address, None, None], - transfer_amount: int, - warm_access: bool, - receiver_initial_balance: int, - track_post_state: bool, - receiver_execution_gas: int = 0, -) -> None: - """Fill a block with ether transfers between the given generators.""" - iteration_cost = ( - fork.transaction_intrinsic_cost_calculator()( - access_list=( - [AccessList(address=Address(0x100), storage_keys=[])] - if warm_access - else None - ), - ) - + receiver_execution_gas + receiver_account_type: ReceiverAccountType, +) -> Tuple[Generator[Address, None, None], Generator[Address, None, None]]: + """Generate sender and receiver generators based on the test case.""" + balance = receiver_account_type.balance + delegation = ( + pre.deploy_contract(code=Op.STOP) + if receiver_account_type.delegated + else None ) - iteration_count = gas_benchmark_value // iteration_cost - txs = [] - token_transfers: dict[Address, int] = {} - for _ in range(iteration_count): - receiver = next(receivers) - token_transfers[receiver] = ( - token_transfers.get(receiver, 0) + transfer_amount - ) - access_list = ( - [AccessList(address=receiver, storage_keys=[])] - if warm_access - else None - ) - txs.append( - Transaction( - to=receiver, - value=transfer_amount, - gas_limit=iteration_cost, - sender=next(senders), - access_list=access_list, - ) - ) + if case_id == "a_to_a": + """Sending to self.""" + senders = get_single_sender_list(pre) + receivers = senders - post_state = ( - { - receiver: Account( - balance=receiver_initial_balance + transferred_amount - ) - for receiver, transferred_amount in token_transfers.items() - if receiver_initial_balance + transferred_amount > 0 - } - if track_post_state - else {} - ) + elif case_id == "a_to_b": + """One sender → one receiver.""" + senders = get_single_sender_list(pre) + receivers = get_single_receiver_list(pre, balance, delegation) - benchmark_test( - pre=pre, - post=post_state, - blocks=[Block(txs=txs)], - expected_benchmark_gas_used=iteration_count * iteration_cost, - ) + elif case_id == "diff_acc_to_b": + """Multiple senders → one receiver.""" + senders = get_distinct_sender_list(pre) + receivers = get_single_receiver_list(pre, balance, delegation) + + elif case_id == "a_to_diff_acc": + """One sender → multiple receivers.""" + senders = get_single_sender_list(pre) + receivers = get_distinct_receiver_list(pre, balance, delegation) + + elif case_id == "diff_acc_to_diff_acc": + """Multiple senders → multiple receivers.""" + senders = get_distinct_sender_list(pre) + receivers = get_distinct_receiver_list(pre, balance, delegation) + + else: + raise ValueError(f"Unknown case: {case_id}") + + return senders, receivers @pytest.mark.parametrize( @@ -224,108 +164,74 @@ def test_ether_transfers( fork: Fork, gas_benchmark_value: int, warm_access: bool, + ether_transfer_case: Tuple[ + Generator[Address, None, None], Generator[Address, None, None] + ], ) -> None: """ - Ether transfers where receivers constructed in pre-allocation. + Single test for ether transfer scenarios. Scenarios: - - a_to_a: self-transfer + - a_to_a: one sender → one sender - a_to_b: one sender → one receiver - diff_acc_to_b: multiple senders → one receiver - a_to_diff_acc: one sender → multiple receivers - diff_acc_to_diff_acc: multiple senders → multiple receivers + + When warm_access is True, each transaction includes an access list + entry for the receiver to warm the account before the transfer. """ + senders, receivers = ether_transfer_case + balance = receiver_account_type.balance - delegation = ( - pre.deploy_contract(code=Op.STOP) - if receiver_account_type.delegated - else None - ) - if case_id == "a_to_a": - senders = get_single_sender_list(pre) - receivers = senders - elif case_id == "a_to_b": - senders = get_single_sender_list(pre) - receivers = get_single_receiver_list(pre, balance, delegation) - elif case_id == "diff_acc_to_b": - senders = get_distinct_sender_list(pre) - receivers = get_single_receiver_list(pre, balance, delegation) - elif case_id == "a_to_diff_acc": - senders = get_single_sender_list(pre) - receivers = get_distinct_receiver_list(pre, balance, delegation) - elif case_id == "diff_acc_to_diff_acc": - senders = get_distinct_sender_list(pre) - receivers = get_distinct_receiver_list(pre, balance, delegation) - else: - raise ValueError(f"Unknown case: {case_id}") + txs = [] + token_transfers: dict[Address, int] = {} - _run_ether_transfer_benchmark( - benchmark_test=benchmark_test, - pre=pre, - fork=fork, - gas_benchmark_value=gas_benchmark_value, - senders=senders, - receivers=receivers, - transfer_amount=transfer_amount, - warm_access=warm_access, - receiver_initial_balance=balance, - track_post_state=(case_id != "a_to_a"), + iteration_cost = fork.transaction_intrinsic_cost_calculator()( + access_list=( + [AccessList(address=Address(0x100), storage_keys=[])] + if warm_access + else None + ), ) + iteration_count = gas_benchmark_value // iteration_cost + for _ in range(iteration_count): + receiver = next(receivers) + token_transfers[receiver] = ( + token_transfers.get(receiver, 0) + transfer_amount + ) + access_list = ( + [AccessList(address=receiver, storage_keys=[])] + if warm_access + else None + ) + txs.append( + Transaction( + to=receiver, + value=transfer_amount, + gas_limit=iteration_cost, + sender=next(senders), + access_list=access_list, + ) + ) -@pytest.mark.parametrize( - "case_id", - [ - "diff_to_nonexistent", - "diff_to_existent", - "diff_to_contract", - ], -) -@pytest.mark.parametrize("transfer_amount", [0, 1]) -def test_ether_transfers_onchain_receivers( - benchmark_test: BenchmarkTestFiller, - pre: Alloc, - case_id: str, - transfer_amount: int, - 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) - """ - senders = get_distinct_sender_list(pre) - receiver_execution_gas = 0 - if case_id == "diff_to_nonexistent": - receivers = get_distinct_nonexistent_receiver_list() - elif case_id == "diff_to_existent": - receivers = get_distinct_existent_receiver_list() - elif case_id == "diff_to_contract": - receivers = get_distinct_contract_receiver_list() - receiver_execution_gas = RECEIVER_CONTRACT_EXECUTION_GAS - else: - raise ValueError(f"Unknown case: {case_id}") + post_state = ( + {} + if case_id == "a_to_a" + else { + receiver: Account(balance=balance + transferred_amount) + for receiver, transferred_amount in token_transfers.items() + if balance + transferred_amount > 0 + } + ) - _run_ether_transfer_benchmark( - benchmark_test=benchmark_test, + benchmark_test( pre=pre, - fork=fork, - gas_benchmark_value=gas_benchmark_value, - senders=senders, - receivers=receivers, - transfer_amount=transfer_amount, - warm_access=False, - receiver_initial_balance=0, - track_post_state=False, - receiver_execution_gas=receiver_execution_gas, + post=post_state, + blocks=[Block(txs=txs)], + expected_benchmark_gas_used=iteration_count * iteration_cost, ) diff --git a/tests/benchmark/stateful/bloatnet/test_transaction_types.py b/tests/benchmark/stateful/bloatnet/test_transaction_types.py new file mode 100644 index 00000000000..90d1d3950a7 --- /dev/null +++ b/tests/benchmark/stateful/bloatnet/test_transaction_types.py @@ -0,0 +1,120 @@ +"""Benchmark ether transfers to receivers that exist on-chain.""" + +import itertools +from typing import Generator + +import pytest +from execution_testing import ( + Address, + Alloc, + BenchmarkTestFiller, + Block, + Fork, + Transaction, + compute_create_address, +) + + +def get_distinct_sender_list(pre: Alloc) -> Generator[Address, None, None]: + """Get a list of distinct sender accounts.""" + while True: + yield pre.fund_eoa() + + +# Bitterex 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 +) + + +# Ether reception cost for Bittrex-created contracts +RECEIVER_CONTRACT_EXECUTION_GAS = 51 + + +def get_distinct_contract_receiver_list() -> Generator[Address, None, None]: + """Yield contract account created by Bitterex controller via CREATE.""" + for nonce in itertools.count(1): + yield compute_create_address( + address=BITTREX_CONTROLLER_ADDRESS, nonce=nonce + ) + + +def get_distinct_existent_receiver_list() -> 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 get_distinct_nonexistent_receiver_list() -> Generator[Address, None, None]: + """Yield non-existent accounts starting from keccak256('random').""" + for address in itertools.count(0xF3CF193BB4AF1022AF7D2089F37D8BAE7157B85F): + yield Address(address) + + +@pytest.mark.parametrize( + "case_id", + [ + "diff_to_nonexistent", + "diff_to_existent", + "diff_to_contract", + ], +) +@pytest.mark.parametrize("transfer_amount", [0, 1]) +def test_ether_transfers_onchain_receivers( + benchmark_test: BenchmarkTestFiller, + pre: Alloc, + case_id: str, + transfer_amount: int, + 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) + """ + senders = get_distinct_sender_list(pre) + receiver_execution_gas = 0 + if case_id == "diff_to_nonexistent": + receivers = get_distinct_nonexistent_receiver_list() + elif case_id == "diff_to_existent": + receivers = get_distinct_existent_receiver_list() + elif case_id == "diff_to_contract": + receivers = get_distinct_contract_receiver_list() + receiver_execution_gas = RECEIVER_CONTRACT_EXECUTION_GAS + else: + 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), + ) + for _ in range(iteration_count) + ] + + benchmark_test( + pre=pre, + post={}, + blocks=[Block(txs=txs)], + expected_benchmark_gas_used=iteration_count * iteration_cost, + ) From 7d841f04c521a163cf979281c04a510391fa5834 Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Wed, 13 May 2026 22:28:49 +0800 Subject: [PATCH 06/10] fix: apply suggested changes --- .../bloatnet/test_transaction_types.py | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/tests/benchmark/stateful/bloatnet/test_transaction_types.py b/tests/benchmark/stateful/bloatnet/test_transaction_types.py index 90d1d3950a7..d2030f4a1d2 100644 --- a/tests/benchmark/stateful/bloatnet/test_transaction_types.py +++ b/tests/benchmark/stateful/bloatnet/test_transaction_types.py @@ -15,13 +15,13 @@ ) -def get_distinct_sender_list(pre: Alloc) -> Generator[Address, None, None]: +def yield_distinct_sender(pre: Alloc) -> Generator[Address, None, None]: """Get a list of distinct sender accounts.""" while True: yield pre.fund_eoa() -# Bitterex controller mainnet address +# 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 @@ -34,15 +34,15 @@ def get_distinct_sender_list(pre: Alloc) -> Generator[Address, None, None]: RECEIVER_CONTRACT_EXECUTION_GAS = 51 -def get_distinct_contract_receiver_list() -> Generator[Address, None, None]: - """Yield contract account created by Bitterex controller via CREATE.""" - for nonce in itertools.count(1): +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 get_distinct_existent_receiver_list() -> Generator[Address, None, None]: +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). @@ -51,12 +51,13 @@ def get_distinct_existent_receiver_list() -> Generator[Address, None, None]: yield Address(address) -def get_distinct_nonexistent_receiver_list() -> Generator[Address, None, None]: +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", [ @@ -85,14 +86,14 @@ def test_ether_transfers_onchain_receivers( - diff_to_contract: distinct contract receivers (matches AccountMode.EXISTING_CONTRACT) """ - senders = get_distinct_sender_list(pre) + senders = yield_distinct_sender(pre) receiver_execution_gas = 0 if case_id == "diff_to_nonexistent": - receivers = get_distinct_nonexistent_receiver_list() + receivers = yield_distinct_nonexistent_receiver() elif case_id == "diff_to_existent": - receivers = get_distinct_existent_receiver_list() + receivers = yield_distinct_existent_receiver() elif case_id == "diff_to_contract": - receivers = get_distinct_contract_receiver_list() + receivers = yield_distinct_contract_receiver() receiver_execution_gas = RECEIVER_CONTRACT_EXECUTION_GAS else: raise ValueError(f"Unknown case: {case_id}") From 6892eb2a39d0d502470175ca38a1ba192aaed530 Mon Sep 17 00:00:00 2001 From: LouisTsai Date: Wed, 13 May 2026 22:36:00 +0800 Subject: [PATCH 07/10] feat: add receipt check --- tests/benchmark/stateful/bloatnet/test_transaction_types.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/benchmark/stateful/bloatnet/test_transaction_types.py b/tests/benchmark/stateful/bloatnet/test_transaction_types.py index d2030f4a1d2..7f966d10896 100644 --- a/tests/benchmark/stateful/bloatnet/test_transaction_types.py +++ b/tests/benchmark/stateful/bloatnet/test_transaction_types.py @@ -118,4 +118,5 @@ def test_ether_transfers_onchain_receivers( post={}, blocks=[Block(txs=txs)], expected_benchmark_gas_used=iteration_count * iteration_cost, + expected_receipt_status=1, ) From 16b73dae5abb3bdeed20ef7e086495577e5b3a56 Mon Sep 17 00:00:00 2001 From: Jochem Brouwer Date: Wed, 13 May 2026 23:18:40 +0200 Subject: [PATCH 08/10] (Claude): add distinct senders --- .../bloatnet/test_transaction_types.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/tests/benchmark/stateful/bloatnet/test_transaction_types.py b/tests/benchmark/stateful/bloatnet/test_transaction_types.py index 7f966d10896..51940945fa9 100644 --- a/tests/benchmark/stateful/bloatnet/test_transaction_types.py +++ b/tests/benchmark/stateful/bloatnet/test_transaction_types.py @@ -5,6 +5,7 @@ import pytest from execution_testing import ( + EOA, Address, Alloc, BenchmarkTestFiller, @@ -14,11 +15,19 @@ compute_create_address, ) +# Deterministic sender pool: keys start at 0x111...111 (32 bytes) and +# increment by 1. Accounts are assumed to be pre-funded on bloatnet +# (e.g. by Spamoor), so they are intentionally NOT added to the pre-alloc. +SENDER_BASE_KEY = ( + 0x1111111111111111111111111111111111111111111111111111111111111111 +) +SENDER_COUNT = 15_000 + -def yield_distinct_sender(pre: Alloc) -> Generator[Address, None, None]: - """Get a list of distinct sender accounts.""" - while True: - yield pre.fund_eoa() +def yield_distinct_sender() -> Generator[EOA, None, None]: + """Yield deterministic sender EOAs pre-funded on-chain.""" + for i in range(SENDER_COUNT): + yield EOA(key=SENDER_BASE_KEY + i) # Bittrex controller mainnet address @@ -86,7 +95,7 @@ def test_ether_transfers_onchain_receivers( - diff_to_contract: distinct contract receivers (matches AccountMode.EXISTING_CONTRACT) """ - senders = yield_distinct_sender(pre) + senders = yield_distinct_sender() receiver_execution_gas = 0 if case_id == "diff_to_nonexistent": receivers = yield_distinct_nonexistent_receiver() From df4d1404512124c343c472bb7b7ff54bba685470 Mon Sep 17 00:00:00 2001 From: Jochem Brouwer Date: Wed, 13 May 2026 23:26:20 +0200 Subject: [PATCH 09/10] (Claude): do not limit distinct senders --- tests/benchmark/stateful/bloatnet/test_transaction_types.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/benchmark/stateful/bloatnet/test_transaction_types.py b/tests/benchmark/stateful/bloatnet/test_transaction_types.py index 51940945fa9..39286705287 100644 --- a/tests/benchmark/stateful/bloatnet/test_transaction_types.py +++ b/tests/benchmark/stateful/bloatnet/test_transaction_types.py @@ -21,12 +21,11 @@ SENDER_BASE_KEY = ( 0x1111111111111111111111111111111111111111111111111111111111111111 ) -SENDER_COUNT = 15_000 def yield_distinct_sender() -> Generator[EOA, None, None]: """Yield deterministic sender EOAs pre-funded on-chain.""" - for i in range(SENDER_COUNT): + for i in itertools.count(0): yield EOA(key=SENDER_BASE_KEY + i) From 147b123736bdc5238e4ee0c4ea90cdc67357651d Mon Sep 17 00:00:00 2001 From: Jochem Brouwer Date: Wed, 13 May 2026 23:58:06 +0200 Subject: [PATCH 10/10] (Claude): add uniq jumpdest contract test --- .../bloatnet/test_transaction_types.py | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/tests/benchmark/stateful/bloatnet/test_transaction_types.py b/tests/benchmark/stateful/bloatnet/test_transaction_types.py index 39286705287..b729f59f8cf 100644 --- a/tests/benchmark/stateful/bloatnet/test_transaction_types.py +++ b/tests/benchmark/stateful/bloatnet/test_transaction_types.py @@ -12,6 +12,7 @@ Block, Fork, Transaction, + compute_create2_address, compute_create_address, ) @@ -42,6 +43,33 @@ def yield_distinct_sender() -> Generator[EOA, None, None]: RECEIVER_CONTRACT_EXECUTION_GAS = 51 +# Arachnid's deterministic deployment proxy. Assumed to have already +# deployed the unique-code contracts via CREATE2 with salts 0, 1, 2, ... +DETERMINISTIC_FACTORY_ADDRESS = Address( + 0x4E59B44847B379578588920CA78FBF26C0B4956C +) + + +# Initcode deployed by DETERMINISTIC_FACTORY_ADDRESS for each +# diff_to_unique_code_jumpdest_contract receiver. Returns a 24,576-byte +# runtime whose entry is PUSH2 0x5fff; JUMP, landing on a JUMPDEST near +# the end of code (then implicit STOP). Each contract embeds its own +# address in code, so the deployed code is unique per address while +# initcode (and therefore the CREATE2 hash input) is shared. +UNIQUE_CODE_JUMPDEST_INITCODE = bytes.fromhex( + "7f5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b6000" + "526020600060205e6040600060405e6080600060805e61010060006101005e61020060" + "006102005e61040060006104005e61080060006108005e61100060006110005e612000" + "60006120005e61400060006140005e7f615fff565b5b5b5b5b5b5b5b5b5b5b5b5b5b5b" + "5b5b5b5b5b5b5b5b5b5b5b5b5b6000527f5b5b5b5b5b5b5b5b5b5b5b5b000000000000" + "000000000000000000000000000030176020526160006000f3" +) + + +# Runtime gas cost: PUSH2 (3) + JUMP (8) + JUMPDEST (1) = 12. +RECEIVER_JUMPDEST_EXECUTION_GAS = 3 + 8 + 1 + + def yield_distinct_contract_receiver() -> Generator[Address, None, None]: """Yield contract account created by Bittrex controller via CREATE.""" for nonce in itertools.count(2): @@ -50,6 +78,23 @@ def yield_distinct_contract_receiver() -> Generator[Address, None, None]: ) +def yield_distinct_unique_code_jumpdest_receiver() -> ( + Generator[Address, None, None] +): + """ + Yield contract addresses deployed by the deterministic CREATE2 factory. + + Each address corresponds to a contract with unique deployed code whose + runtime executes PUSH2 + JUMP + JUMPDEST (12 gas). + """ + for salt in itertools.count(0): + yield compute_create2_address( + address=DETERMINISTIC_FACTORY_ADDRESS, + salt=salt, + initcode=UNIQUE_CODE_JUMPDEST_INITCODE, + ) + + def yield_distinct_existent_receiver() -> Generator[Address, None, None]: """ Yield existing balance-only EOA on bloatnet. pre-funded by Spamoor @@ -72,6 +117,7 @@ def yield_distinct_nonexistent_receiver() -> Generator[Address, None, None]: "diff_to_nonexistent", "diff_to_existent", "diff_to_contract", + "diff_to_unique_code_jumpdest_contract", ], ) @pytest.mark.parametrize("transfer_amount", [0, 1]) @@ -93,6 +139,9 @@ def test_ether_transfers_onchain_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; runtime executes + PUSH2 + JUMP + JUMPDEST. """ senders = yield_distinct_sender() receiver_execution_gas = 0 @@ -103,6 +152,9 @@ def test_ether_transfers_onchain_receivers( elif case_id == "diff_to_contract": receivers = yield_distinct_contract_receiver() receiver_execution_gas = RECEIVER_CONTRACT_EXECUTION_GAS + elif case_id == "diff_to_unique_code_jumpdest_contract": + receivers = yield_distinct_unique_code_jumpdest_receiver() + receiver_execution_gas = RECEIVER_JUMPDEST_EXECUTION_GAS else: raise ValueError(f"Unknown case: {case_id}")