Skip to content

test_sstore_refund_quotient_cap()

Documentation for tests/amsterdam/eip8038_state_access_gas_cost_increase/test_sstore_refunds.py::test_sstore_refund_quotient_cap@343274cc.

Generate fixtures for these test cases for Amsterdam with:

fill -v tests/amsterdam/eip8038_state_access_gas_cost_increase/test_sstore_refunds.py::test_sstore_refund_quotient_cap --fork Amsterdam

The applied refund saturates at the EIP-3529 quotient cap.

num_clears distinct non-zero-original slots are each cleared, accruing num_clears * REFUND_STORAGE_CLEAR into refund_counter. A single clear's gross gas is small enough that gas_used // 5 is always below the accrued refund, so the applied refund is the cap and cumulative_gas_used reflects min(gas_used // 5, accrued).

Source code in tests/amsterdam/eip8038_state_access_gas_cost_increase/test_sstore_refunds.py
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
@EIPChecklist.GasRefundsChanges.Test.RefundCalculation()
@EIPChecklist.GasRefundsChanges.Test.RefundCalculation.Exact()
@pytest.mark.parametrize("num_clears", [1, 8, 32])
def test_sstore_refund_quotient_cap(
    state_test: StateTestFiller,
    pre: Alloc,
    fork: Fork,
    num_clears: int,
) -> None:
    """
    The applied refund saturates at the EIP-3529 quotient cap.

    ``num_clears`` distinct non-zero-original slots are each cleared,
    accruing ``num_clears * REFUND_STORAGE_CLEAR`` into ``refund_counter``.
    A single clear's gross gas is small enough that ``gas_used // 5`` is
    always below the accrued refund, so the applied refund is the cap and
    ``cumulative_gas_used`` reflects ``min(gas_used // 5, accrued)``.
    """
    code = Bytecode()
    for slot in range(num_clears):
        code += Op.SSTORE.with_metadata(
            key_warm=False,
            original_value=1,
            current_value=1,
            new_value=0,
        )(slot, 0)

    contract = pre.deploy_contract(
        code=code,
        storage=dict.fromkeys(range(num_clears), 1),
    )

    # num_clears distinct clears accrue num_clears * REFUND_STORAGE_CLEAR.
    accrued = code.refund(fork)
    intrinsic = fork.transaction_intrinsic_cost_calculator()(
        return_cost_deducted_prior_execution=True
    )
    gross = intrinsic + code.execution_cost(fork)
    # The cap binds for every parametrization (single-clear gross is far
    # below 5x a clear refund).
    cap = gross // 5
    assert cap < accrued
    applied_refund = min(cap, accrued)
    expected_cumulative = gross - applied_refund

    tx = Transaction(
        to=contract,
        sender=pre.fund_eoa(),
        expected_receipt=TransactionReceipt(
            cumulative_gas_used=expected_cumulative
        ),
    )

    post = {contract: Account(storage=dict.fromkeys(range(num_clears), 0))}
    state_test(pre=pre, post=post, tx=tx)

Parametrized Test Cases

This test generates 3 parametrized test cases across 1 fork.