@pytest.mark.parametrize("access_warm", [True, False])
@pytest.mark.parametrize("sloads_before_sstore", [True, False])
@pytest.mark.parametrize(
"initial_value,write_value",
[
pytest.param(0, 0, id="zero_to_zero"),
pytest.param(0, 0xDEADBEEF, id="zero_to_nonzero"),
# TODO: Resolve refund mechanism
# pytest.param(0xDEADBEEF, 0, id="nonzero_to_zero"),
pytest.param(0xDEADBEEF, 0xBEEFBEEF, id="nonzero_to_diff"),
pytest.param(0xDEADBEEF, 0xDEADBEEF, id="nonzero_to_same"),
],
)
def test_sstore_variants(
benchmark_test: BenchmarkTestFiller,
fork: Fork,
pre: Alloc,
tx_gas_limit: int,
gas_benchmark_value: int,
access_warm: bool,
sloads_before_sstore: bool,
initial_value: int,
write_value: int,
) -> None:
"""
Benchmark SSTORE instruction with various configurations.
Uses EIP-7702 delegation. The authority EOA delegates to:
- StorageInitializer: storage[i] = initial_value (initial_value != 0)
- BenchmarkExecutor: performs the benchmark operation (SSTORE)
Variants:
- access_warm: Warm storage slots via access list
- sloads_before_sstore: SLOADs per slot before SSTORE
- initial_value/write_value: Storage transitions
(zero_to_zero, zero_to_nonzero, nonzero_to_zero, nonzero_to_nonzero)
"""
# Initial Storage Construction
initializer_code = create_sstore_initializer(initial_value)
initializer_addr = pre.deploy_contract(code=initializer_code)
# Actual Benchmark Execution
executor_code = create_sstore_executor(
sloads_before_sstore=sloads_before_sstore,
key_warm=access_warm,
original_value=initial_value,
new_value=write_value,
)
executor_addr = pre.deploy_contract(code=executor_code)
authority = pre.fund_eoa(amount=0)
authority_nonce = 0
delegation_sender = pre.fund_eoa()
calldata_gen = partial(
executor_calldata_generator, write_value=write_value
)
access_list_gen = partial(
access_list_generator, access_warm=access_warm, authority=authority
)
# Number of slots that can be processed in the execution phase
num_target_slots = sum(
executor_code.tx_iterations_by_gas_limit(
fork=fork,
gas_limit=gas_benchmark_value,
calldata=calldata_gen,
access_list=access_list_gen,
start_iteration=1,
recipient_type=RecipientType.DELEGATION_7702,
)
)
# Setup phase: initialize storage slots (if initial_value != 0)
with TestPhaseManager.setup():
blocks = build_delegated_storage_setup(
pre=pre,
fork=fork,
tx_gas_limit=tx_gas_limit,
block_gas_budget=gas_benchmark_value,
needs_init=initial_value != 0,
num_target_slots=num_target_slots,
initializer_code=initializer_code,
initializer_addr=initializer_addr,
executor_addr=executor_addr,
authority=authority,
authority_nonce=authority_nonce,
delegation_sender=delegation_sender,
initializer_calldata_generator=initializer_calldata_generator,
)
# Execution phase
expected_gas_used = 0
with TestPhaseManager.execution():
exec_txs = list(
executor_code.transactions_by_gas_limit(
fork=fork,
gas_limit=gas_benchmark_value,
sender=pre.fund_eoa(),
to=authority,
calldata=calldata_gen,
start_iteration=1,
access_list=access_list_gen,
recipient_type=RecipientType.DELEGATION_7702,
)
)
expected_gas_used = sum(tx.gas_cost for tx in exec_txs)
blocks.append(Block(txs=exec_txs))
benchmark_test(
pre=pre,
blocks=blocks,
expected_benchmark_gas_used=expected_gas_used,
)